diff --git a/templates/widget/fetchPoWConfig.ts b/templates/widget/fetchPoWConfig.ts
index f45da555..7221d40d 100644
--- a/templates/widget/fetchPoWConfig.ts
+++ b/templates/widget/fetchPoWConfig.ts
@@ -11,17 +11,12 @@
 
 import genJsonPayload from "../utils/genJsonPayload";
 import * as CONST from "./const";
+import { PoWConfig } from "./types";
 
 type GetConfigPayload = {
   key: string;
 };
 
-export type PoWConfig = {
-  string: string;
-  difficulty_factor: number;
-  salt: string;
-};
-
 /**
  * fetch proof-of-work configuration
  * @returns {PoWConfig} pow config
diff --git a/templates/widget/index.ts b/templates/widget/index.ts
index 545abd3e..2b5582da 100644
--- a/templates/widget/index.ts
+++ b/templates/widget/index.ts
@@ -9,7 +9,7 @@
  * MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
  */
 
-import prove from "./prove";
+import { Work, ServiceWorkerWork } from "./types";
 import fetchPoWConfig from "./fetchPoWConfig";
 import sendWork from "./sendWork";
 import sendToParent from "./sendToParent";
@@ -18,6 +18,7 @@ import * as CONST from "./const";
 import "./main.scss";
 
 let LOCK = false;
+const worker = new Worker("/bench.js");
 
 /** add  mcaptcha widget element to DOM */
 export const registerVerificationEventHandler = (): void => {
@@ -49,15 +50,30 @@ export const solveCaptchaRunner = async (e: Event): Promise<void> => {
     // 1. get config
     const config = await fetchPoWConfig();
     // 2. prove work
-    const proof = await prove(config);
-    // 3. submit work
-    const token = await sendWork(proof);
-    // 4. send token
-    sendToParent(token);
-    // 5. mark checkbox checked
-    CONST.btn().checked = true;
-    CONST.messageText().after();
-    LOCK = false;
+    worker.postMessage(config);
+
+    worker.onmessage = async (event: MessageEvent) => {
+      const resp: ServiceWorkerWork = event.data;
+      console.log(
+        `Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.duration}`
+      );
+
+      const proof: Work = {
+        key: CONST.sitekey(),
+        string: config.string,
+        nonce: resp.work.nonce,
+        result: resp.work.result,
+      };
+
+      // 3. submit work
+      const token = await sendWork(proof);
+      // 4. send token
+      sendToParent(token);
+      // 5. mark checkbox checked
+      CONST.btn().checked = true;
+      CONST.messageText().after();
+      LOCK = false;
+    };
   } catch (e) {
     CONST.messageText().error();
     console.error(e);
diff --git a/templates/widget/prove.ts b/templates/widget/prove.ts
index b6bc3208..b23da88b 100644
--- a/templates/widget/prove.ts
+++ b/templates/widget/prove.ts
@@ -10,27 +10,14 @@
  */
 
 import { gen_pow } from "@mcaptcha/pow-wasm";
-import { PoWConfig } from "./fetchPoWConfig";
-import * as CONST from "./const";
-
-export type Work = {
-  result: string;
-  nonce: number;
-  string: string;
-  key: string;
-};
-
-type WasmWork = {
-  result: string;
-  nonce: number;
-};
+import { WasmWork, PoWConfig } from "./types";
 
 /**
  * proove work
  * @param {PoWConfig} config - the proof-of-work configuration using which
  * work needs to be computed
  * */
-const prove = async (config: PoWConfig): Promise<Work> => {
+const prove = (config: PoWConfig): WasmWork => {
   const proofString = gen_pow(
     config.salt,
     config.string,
@@ -38,14 +25,7 @@ const prove = async (config: PoWConfig): Promise<Work> => {
   );
   const proof: WasmWork = JSON.parse(proofString);
 
-  const res: Work = {
-    key: CONST.sitekey(),
-    string: config.string,
-    nonce: proof.nonce,
-    result: proof.result,
-  };
-
-  return res;
+  return proof;
 };
 
 export default prove;
diff --git a/templates/widget/sendToParent.ts b/templates/widget/sendToParent.ts
index ba54da64..f2fc7c1c 100644
--- a/templates/widget/sendToParent.ts
+++ b/templates/widget/sendToParent.ts
@@ -8,7 +8,7 @@
  * this program. If not, see <https://spdx.org/licenses/MIT.html> for
  * MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
  */
-import {Token} from "./sendWork";
+import {Token} from "./types";
 
 /**
  * send pow validation token as message to parant of the iframe
diff --git a/templates/widget/sendWork.ts b/templates/widget/sendWork.ts
index 248f5c44..8ca7f872 100644
--- a/templates/widget/sendWork.ts
+++ b/templates/widget/sendWork.ts
@@ -11,11 +11,7 @@
 
 import genJsonPayload from "../utils/genJsonPayload";
 import * as CONST from "./const";
-import {Work} from "./prove";
-
-export type Token = {
-  token: string;
-};
+import { Work, Token } from "./types";
 
 export const sendWork = async (payload: Work): Promise<Token> => {
   try {
@@ -33,7 +29,7 @@ export const sendWork = async (payload: Work): Promise<Token> => {
   } catch (err) {
     CONST.messageText().error();
     console.error(err);
-    await new Promise(r => setTimeout(r, 1000));
+    await new Promise((r) => setTimeout(r, 1000));
     window.location.reload();
     throw err;
   }
diff --git a/templates/widget/service-worker.ts b/templates/widget/service-worker.ts
new file mode 100644
index 00000000..5cfbb76e
--- /dev/null
+++ b/templates/widget/service-worker.ts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021  Aravinth Manivannan <realaravinth@batsense.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+import prove from "./prove";
+import { PoWConfig, ServiceWorkerWork } from "./types";
+import log from "../logger";
+
+log.log("worker registered");
+onmessage = (e) => {
+  console.debug("message received at worker");
+  const config: PoWConfig = e.data;
+
+  const t0 = performance.now();
+  const work = prove(config);
+
+  const t1 = performance.now();
+  const duration = t1 - t0;
+
+  const res: ServiceWorkerWork = {
+    work,
+    duration,
+  };
+
+  postMessage(res);
+};
diff --git a/templates/widget/types.ts b/templates/widget/types.ts
new file mode 100644
index 00000000..b01dfb0c
--- /dev/null
+++ b/templates/widget/types.ts
@@ -0,0 +1,37 @@
+/*
+ * mCaptcha is a PoW based DoS protection software.
+ * This is the frontend web component of the mCaptcha system
+ * Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
+ *
+ * Use of this source code is governed by Apache 2.0 or MIT license.
+ * You shoud have received a copy of MIT and Apache 2.0 along with
+ * this program. If not, see <https://spdx.org/licenses/MIT.html> for
+ * MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
+ */
+
+export type Work = {
+  result: string;
+  nonce: number;
+  string: string;
+  key: string;
+};
+
+export type WasmWork = {
+  result: string;
+  nonce: number;
+};
+
+export type ServiceWorkerWork = {
+  work: WasmWork;
+  duration: number;
+};
+
+export type PoWConfig = {
+  string: string;
+  difficulty_factor: number;
+  salt: string;
+};
+
+export type Token = {
+  token: string;
+};
diff --git a/webpack.config.js b/webpack.config.js
index 525efda5..bb5fb717 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -12,6 +12,7 @@ module.exports = {
     bundle: "./templates/index.ts",
     mobile: "./templates/mobile.ts",
     verificationWidget: "./templates/widget/index.ts",
+    bench: "./templates/widget/service-worker.ts",
   },
   output: {
     filename: "[name].js",