diff --git a/Cargo.lock b/Cargo.lock
index c09ed45733408cb576e37fb98b54596ab3a90512..57c70150a20725e002140ed290b3b1987d01cf76 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18126,6 +18126,7 @@ dependencies = [
  "sc-consensus-manual-seal",
  "sc-executor 0.32.0",
  "sc-network",
+ "sc-offchain",
  "sc-rpc",
  "sc-runtime-utilities",
  "sc-service",
@@ -18133,6 +18134,7 @@ dependencies = [
  "sc-telemetry",
  "sc-tracing",
  "sc-transaction-pool",
+ "sc-transaction-pool-api",
  "scale-info",
  "serde",
  "serde_json",
@@ -18145,6 +18147,7 @@ dependencies = [
  "sp-genesis-builder 0.8.0",
  "sp-inherents 26.0.0",
  "sp-keystore 0.34.0",
+ "sp-offchain 26.0.0",
  "sp-runtime 31.0.1",
  "sp-session 27.0.0",
  "sp-storage 19.0.0",
diff --git a/cumulus/polkadot-omni-node/lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml
index 018fc88a2aeaf2018681e96a7e4baccaa17b2afa..020d980d3d9d6f96ed05f6afa474f695873d40d9 100644
--- a/cumulus/polkadot-omni-node/lib/Cargo.toml
+++ b/cumulus/polkadot-omni-node/lib/Cargo.toml
@@ -50,6 +50,7 @@ sc-consensus = { workspace = true, default-features = true }
 sc-consensus-manual-seal = { workspace = true, default-features = true }
 sc-executor = { workspace = true, default-features = true }
 sc-network = { workspace = true, default-features = true }
+sc-offchain = { workspace = true, default-features = true }
 sc-rpc = { workspace = true, default-features = true }
 sc-runtime-utilities = { workspace = true, default-features = true }
 sc-service = { workspace = true, default-features = true }
@@ -57,6 +58,7 @@ sc-sysinfo = { workspace = true, default-features = true }
 sc-telemetry = { workspace = true, default-features = true }
 sc-tracing = { workspace = true, default-features = true }
 sc-transaction-pool = { workspace = true, default-features = true }
+sc-transaction-pool-api = { workspace = true, default-features = true }
 sp-api = { workspace = true, default-features = true }
 sp-block-builder = { workspace = true, default-features = true }
 sp-consensus = { workspace = true, default-features = true }
@@ -66,6 +68,7 @@ sp-crypto-hashing = { workspace = true }
 sp-genesis-builder = { workspace = true }
 sp-inherents = { workspace = true, default-features = true }
 sp-keystore = { workspace = true, default-features = true }
+sp-offchain = { workspace = true, default-features = true }
 sp-runtime = { workspace = true }
 sp-session = { workspace = true, default-features = true }
 sp-storage = { workspace = true, default-features = true }
diff --git a/cumulus/polkadot-omni-node/lib/src/common/mod.rs b/cumulus/polkadot-omni-node/lib/src/common/mod.rs
index 37660a5347a20b8fad5b6452eed331f98806c8d7..843183425dabfa44f481855691dfaba69cd056fa 100644
--- a/cumulus/polkadot-omni-node/lib/src/common/mod.rs
+++ b/cumulus/polkadot-omni-node/lib/src/common/mod.rs
@@ -28,6 +28,7 @@ pub mod types;
 
 use cumulus_primitives_core::{CollectCollationInfo, GetCoreSelectorApi};
 use sc_client_db::DbHash;
+use sc_offchain::OffchainWorkerApi;
 use serde::de::DeserializeOwned;
 use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata};
 use sp_block_builder::BlockBuilder;
@@ -65,6 +66,7 @@ pub trait NodeRuntimeApi<Block: BlockT>:
 	+ SessionKeys<Block>
 	+ BlockBuilder<Block>
 	+ TaggedTransactionQueue<Block>
+	+ OffchainWorkerApi<Block>
 	+ CollectCollationInfo<Block>
 	+ GetCoreSelectorApi<Block>
 	+ Sized
@@ -77,6 +79,7 @@ impl<T, Block: BlockT> NodeRuntimeApi<Block> for T where
 		+ SessionKeys<Block>
 		+ BlockBuilder<Block>
 		+ TaggedTransactionQueue<Block>
+		+ OffchainWorkerApi<Block>
 		+ GetCoreSelectorApi<Block>
 		+ CollectCollationInfo<Block>
 {
diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs
index 868368f3ca1a7b2179854ad77cbba52bf97ae5a0..d497337904b9798fcaaa2aa5d78853d33b959fb8 100644
--- a/cumulus/polkadot-omni-node/lib/src/common/spec.rs
+++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs
@@ -30,9 +30,11 @@ use cumulus_client_service::{
 };
 use cumulus_primitives_core::{BlockT, ParaId};
 use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
+use futures::FutureExt;
 use parachains_common::Hash;
 use polkadot_primitives::CollatorPair;
 use prometheus_endpoint::Registry;
+use sc_client_api::Backend;
 use sc_consensus::DefaultImportQueue;
 use sc_executor::{HeapAllocStrategy, DEFAULT_HEAP_ALLOC_STRATEGY};
 use sc_network::{config::FullNetworkConfiguration, NetworkBackend, NetworkBlock};
@@ -41,6 +43,7 @@ use sc_sysinfo::HwBench;
 use sc_telemetry::{TelemetryHandle, TelemetryWorker};
 use sc_tracing::tracing::Instrument;
 use sc_transaction_pool::TransactionPoolHandle;
+use sc_transaction_pool_api::OffchainTransactionPoolFactory;
 use sp_keystore::KeystorePtr;
 use std::{future::Future, pin::Pin, sync::Arc, time::Duration};
 
@@ -303,6 +306,27 @@ pub(crate) trait NodeSpec: BaseNodeSpec {
 				})
 				.await?;
 
+			if parachain_config.offchain_worker.enabled {
+				let offchain_workers =
+					sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
+						runtime_api_provider: client.clone(),
+						keystore: Some(params.keystore_container.keystore()),
+						offchain_db: backend.offchain_storage(),
+						transaction_pool: Some(OffchainTransactionPoolFactory::new(
+							transaction_pool.clone(),
+						)),
+						network_provider: Arc::new(network.clone()),
+						is_validator: parachain_config.role.is_authority(),
+						enable_http_requests: false,
+						custom_extensions: move |_| vec![],
+					})?;
+				task_manager.spawn_handle().spawn(
+					"offchain-workers-runner",
+					"offchain-work",
+					offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
+				);
+			}
+
 			let rpc_builder = {
 				let client = client.clone();
 				let transaction_pool = transaction_pool.clone();
diff --git a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs
index 6bfd5f4f4cbd1743782303d0d5f6ab78d16c7b4a..915f156f8cb53ceee4b4d5976297586f11438f96 100644
--- a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs
+++ b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs
@@ -111,6 +111,12 @@ macro_rules! impl_node_runtime_apis {
 				}
 			}
 
+			impl sp_offchain::OffchainWorkerApi<$block> for $runtime {
+				fn offchain_worker(_: &<$block as BlockT>::Header) {
+					unimplemented!()
+				}
+			}
+
 			impl sp_session::SessionKeys<$block> for $runtime {
 				fn generate_session_keys(_: Option<Vec<u8>>) -> Vec<u8> {
 					unimplemented!()
diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs
index 92a55b2adbea16fa232013c31bee3dcd80542d24..96802177ec1049e5b508015cca634636b894355a 100644
--- a/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs
+++ b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs
@@ -23,12 +23,15 @@ use codec::Encode;
 use cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig};
 use cumulus_primitives_aura::AuraUnincludedSegmentApi;
 use cumulus_primitives_core::{CollectCollationInfo, ParaId};
+use futures::FutureExt;
 use polkadot_primitives::UpgradeGoAhead;
+use sc_client_api::Backend;
 use sc_consensus::{DefaultImportQueue, LongestChain};
 use sc_consensus_manual_seal::rpc::{ManualSeal, ManualSealApiServer};
 use sc_network::NetworkBackend;
 use sc_service::{Configuration, PartialComponents, TaskManager};
 use sc_telemetry::TelemetryHandle;
+use sc_transaction_pool_api::OffchainTransactionPoolFactory;
 use sp_api::{ApiExt, ProvideRuntimeApi};
 use sp_runtime::traits::Header;
 use std::{marker::PhantomData, sync::Arc};
@@ -118,6 +121,27 @@ impl<NodeSpec: NodeSpecT> ManualSealNode<NodeSpec> {
 				metrics,
 			})?;
 
+		if config.offchain_worker.enabled {
+			let offchain_workers =
+				sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
+					runtime_api_provider: client.clone(),
+					keystore: Some(keystore_container.keystore()),
+					offchain_db: backend.offchain_storage(),
+					transaction_pool: Some(OffchainTransactionPoolFactory::new(
+						transaction_pool.clone(),
+					)),
+					network_provider: Arc::new(network.clone()),
+					is_validator: config.role.is_authority(),
+					enable_http_requests: true,
+					custom_extensions: move |_| vec![],
+				})?;
+			task_manager.spawn_handle().spawn(
+				"offchain-workers-runner",
+				"offchain-work",
+				offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
+			);
+		}
+
 		let proposer = sc_basic_authorship::ProposerFactory::new(
 			task_manager.spawn_handle(),
 			client.clone(),
diff --git a/prdoc/pr_7479.prdoc b/prdoc/pr_7479.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..444eaa420a4562ebe2ad0bb298b197fd83e5f036
--- /dev/null
+++ b/prdoc/pr_7479.prdoc
@@ -0,0 +1,9 @@
+title: 'omni-node: add offchain worker'
+doc:
+- audience: [ Runtime Dev, Node Dev, Node Operator ]
+  description: |-
+    Added support for offchain worker to omni-node-lib for both aura and manual seal nodes.
+
+crates:
+- name: polkadot-omni-node-lib
+  bump: patch