Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

WebDecoy at your edge

Deployable WebDecoy components that run in front of your origin. It fails open: on any error — can't reach WebDecoy, can't verify a token, anything unexpected — the request is forwarded untouched, so it cannot take your site down.

  • Cloudflare → this repo root, a Worker. Does both jobs below.
  • AWS / CloudFrontaws/, a Lambda@Edge function. Enforcement only.

The two jobs

Enforcement. Validates wd_clearance tokens at the edge, so a client that has been denied is stopped before it reaches your origin.

Detection. Reports automated clients that never execute JavaScript — Googlebot's crawl pass, GPTBot, ClaudeBot, CCBot, curl, most scrapers.

That second one is not a nice-to-have. WebDecoy's page tag runs in the visitor's browser, which is the impossible place to observe a client that never opens one. On a JavaScript-only install your Citation Monitor can only ever show browser extensions and LLM referrals — never a crawler. This Worker is the only thing that closes that gap.

Detection never blocks, challenges, or modifies a response. It is a sensor. Enforcement is the part that acts, and only on clients you have already denied.

Cloudflare (one click)

Deploy to Cloudflare

Cloudflare clones this repository into your own GitHub or GitLab account and deploys it to your Cloudflare account. Set two variables:

VariableWhat it is
WD_SITE_KEYYour WebDecoy organization id. Integrations → Cloudflare in the app.
WD_API_BASELeave as https://ingest.webdecoy.com unless told otherwise.

Without a correct WD_SITE_KEY the Worker runs and reports under no organization, which looks identical to it not working.

Then bind a route — this part is not automatic

Deploying a Worker does not put it in the request path. Until you add a route it runs for nothing. Workers & Pages → your Worker → Settings → Domains & Routes → Add route:

example.com/*

The WebDecoy app can deploy and bind routes for you in one step — Integrations → Cloudflare → Edge Sensor. This repository is for people who prefer to own the deployment.

Then check the record is proxied

Worker routes only fire on proxied (orange-cloud) DNS records. On a DNS-only record Cloudflare accepts the route and the Worker never runs — the install looks successful and reports nothing, indefinitely. Confirm the orange cloud in DNS → Records.

Invocations

The Worker consumes an invocation for every request it runs on; Workers' free tier is 100,000/day. Routes bound to no script stop any Worker running on a more specific path, because Cloudflare matches most-specific-first. Adding these keeps it off asset traffic:

/_astro/* /_next/* /_nuxt/* /_app/* /assets/* /static/*
/build/* /dist/* /wp-content/* /wp-includes/* /cdn-cgi/*

They affect every Worker on those paths, not just this one.

Uninstall

Delete the route first, then the Worker. Deleting the Worker while a route still points at it leaves the route referencing a script that no longer exists, and your visitors are what discovers that.

Privacy

The beacon carries request metadata — user agent, path, IP, TLS and header characteristics. It does not carry request or response bodies, cookies, or credentials.

worker.js is generated

It is published byte-identical to the script WebDecoy's one-click installer deploys, so both paths run the same code. aws/ is maintained as source.

Please do not send pull requests against worker.js; they cannot be merged. Open an issue, or mail support@webdecoy.com.

About

Deployable edge validators for WebDecoy clearance enforcement — Cloudflare Worker + AWS Lambda@Edge

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages