WP Manifestindependent plugin directory
manifest / security / scrapelock-wp

ScrapeLock – Content & AI Bot Protection

Content & AI Bot Protection for WordPress: blocks scrapers and AI crawlers, rate limits, Lockdown with 2FA and file integrity. Topics: wordpress, wordpress-plugin, anti-scraping, ai-crawlers, security, bot-protection

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/code-bunnyhub/scrapelock-wp/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

ScrapeLock – stops scrapers and AI bots on the server, not just in the browser

ScrapeLock – Content & AI Bot Protection

Server-side anti-scraping and site lockdown for WordPress and WooCommerce, by CodeBunny. Formerly Content Protect.

Most content protection plugins disable right click in the browser. Scrapers and AI crawlers never use a browser, so they are not affected. ScrapeLock works on the server, where automated copying actually happens, and keeps real visitors, customers and search engines unaffected. Lockdown adds what no firewall does: once you are logged in, nothing can be changed until you unlock the site with a code from your phone.

  • Free, GPL-2.0-or-later. No premium version, no license checks, no tracking.
  • WordPress 6.2+ (tested up to 7.2), PHP 7.4+, WooCommerce-aware.

Features

Bots and limits

  • Real search engines vs. fakes. Googlebot, Bingbot, Applebot and Yandex are verified against their official IP lists and with reverse + forward DNS. Real crawlers are never limited; impostors get a 403.
  • AI training vs. AI search. Training crawlers (GPTBot, ClaudeBot, CCBot, Google-Extended, Bytespider…) are blocked; AI search assistants (OAI-SearchBot, ChatGPT-User, PerplexityBot…) can be allowed with one option and verified against their official IP lists.
  • Per-IP limits for pages, searches, REST / GraphQL, 404s and sitemaps (IPv6: per /64, optionally also per /56), with temporary blocks for repeat offenders and an invisible bot trap.
  • Stricter limit for data centers: visitors from the published addresses of AWS, Google Cloud, Oracle Cloud, DigitalOcean and Akamai / Linode (where scrapers run, people rarely browse) get a lower page limit.
  • Human check without a captcha: a light proof-of-work after the first real interaction; visitors without it get a stricter limit, not a block.
  • Headless and fake browsers that reveal themselves in their headers are blocked.
  • Country rules from Cloudflare's or Bunny CDN's country header, or the free DB-IP Lite database.
  • Real visitor IP behind Cloudflare, Bunny CDN or your own proxy, trusted only when the request really comes from it.

Content, feeds and API

  • Text hidden from the REST API, WPGraphQL and full-text RSS for visitors.
  • Private XML feeds (price comparison sites, Google Merchant, ERP) protected with a token in a header or the URL. Only the token hash is stored; rotation with a grace period.
  • Optional: hide the REST API index from visitors, turn off pingbacks, and see which REST routes anyone can call.
  • Hide versions of WordPress, PHP and the plugins (generator tags, ?ver=, X-Powered-By, and readme / changelog files through the server rules), so scanners cannot match them against lists of known vulnerabilities.
  • Optional: excerpts instead of the full text on lists of articles (home, categories, search), and blocking of web archives (Wayback Machine).
  • Usernames hidden from ?author=N, the users endpoint, the sitemap and oEmbed.

On the page and images

  • Copy, right click, drag and print protection (or copy with a source link), blur on screenshot shortcuts, no framing by other sites.
  • Machine-readable AI opt-out (TDM): header, meta tag and /.well-known/tdmrep.json.
  • Watermarks, never applied twice, with the clean original kept.

Server and CDN

  • Ready-made Nginx, Apache and Cloudflare rules generated for your own site and settings.
  • Optional blocking at the CDN (3.1): the IPs ScrapeLock blocks temporarily are also blocked by Cloudflare or Bunny CDN with your own account, and removed there when the block ends, so a persistent scraper is stopped before it reaches your server.
  • Optional only through the CDN (3.2): requests that go straight to the server's own address, around the CDN, get a 403.
  • Optional early check (mu-plugin) and pre-cache check (one line in wp-config.php) so pages served from a page cache are protected too.
  • Emergency Mode: one click for stricter limits during an attack, for 1 hour to 3 days, or automatically when the whole site gets five times its usual pages per minute for 3 minutes in a row (a scraper spread over many IPs).

Lockdown

Freeze the whole site with one click and a code from your authenticator app (Google Authenticator, Microsoft Authenticator, Authy…).

  • While locked, users with a frozen role keep only read: nobody can install, update or activate plugins and themes, run updates, use the file editor, add users or administrators, change roles, staff emails or passwords, settings or content, from wp-admin, the REST API or XML-RPC.
  • Enforced against code too: protected options (active plugins, theme, site address, admin email, registration, default role, user roles, uploads folder, search engine visibility), role changes, staff email and password changes, password resets and new application passwords are refused while locked.
  • Visitors, customers, orders, payments, webhooks, cron jobs and members who post their own content keep working.
  • TOTP (RFC 6238), each code accepted once even under concurrent requests (database compare-and-set), the secret encrypted with libsodium using the keys in wp-config.php, ten one-time recovery codes stored only as hashes, wrong-code limits and an email on every unlock.
  • Temporary unlock (15 minutes to 2 hours, then it locks again by itself). A clear "The site is locked" page with an unlock button for administrators.
  • No WP-CLI command and no ability can unlock it.
  • Sealed against database tampering (3.3): the lock and the file fingerprint are signed (HMAC-SHA256, key derived from AUTH_KEY/AUTH_SALT in wp-config.php), and a must-use plugin (scrapelock-lockdown-guard.php) keeps a signed copy of the lock outside the database. SQL injection in another plugin cannot unlock the site: protected options changed in the database are put back, and accounts made administrator behind WordPress's back cannot sign in. A temporary unlock gives the rights back only to the administrator who unlocked.
  • File integrity: a fingerprint of every PHP, .htaccess and .user.ini file is taken when you lock and checked every hour; WordPress and the plugins from WordPress.org are also compared with their official checksums. A new or changed file (usually a backdoor uploaded through a vulnerable plugin) is emailed to you; optional quarantine deactivates the plugin and renames new PHP files in the uploads folder.
  • No PHP in the uploads folder: .htaccess for Apache and a rule for Nginx.

Lockdown complements a firewall such as Wordfence: the firewall and two-factor login guard the door, Lockdown guards what happens after someone is inside, for example with a stolen session cookie.

Tools

  • Site Health tests and a ScrapeLock section on the Info tab.
  • WP-CLI: wp scrapelock status | block | unblock | blocked | emergency | log.
  • Abilities API (WordPress 6.9+): scrapelock/get-summary, block-ip, unblock-ip, emergency-mode, for administrators only.
  • Block log with a 24-hour summary, top IPs, User-Agents and the pages scrapers were after.

Forms, cart, checkout, the WooCommerce Store API and payment webhooks are never affected.

Screenshots

Block log Bots and limits
Block log: summary by reason, top IPs and User-Agents Bots and limits: AI crawlers, fake search engines, bot trap
Feeds and API Server rules
Token-protected feeds, text hidden from REST, GraphQL and RSS Cloudflare, Nginx and Apache rules for your own site
Presets and Emergency Mode Dashboard widget
Presets, Emergency Mode and on-page protection Dashboard widget: protection status and the last 24 hours

Installation

  1. Download scrapelock.zip from the latest release.
  2. In WordPress: Plugins → Add New → Upload Plugin, choose the zip, then Activate.
  3. Open Settings → ScrapeLock, pick a preset (Balanced is a good start) and check the Real visitor IP setting if your site is behind a CDN.

The full description for the WordPress.org directory is in readme.txt. A user guide in Greek is in docs/user-guide-el.md.

Upgrading from Content Protect

Deactivate Content Protect (folder content-protect) and activate ScrapeLock. Settings, feed tokens and the block log are kept. If you pasted the old Apache rules, replace the # BEGIN Content Protect block with the new # BEGIN ScrapeLock block from the "Server rules" tab.

Repository layout

Path Contents
scrapelock.php, includes/, assets/, languages/, uninstall.php, readme.txt The plugin, as installed in wp-content/plugins/scrapelock/
tests/ Tests on a real WordPress (HTTP, watermark, admin, Lockdown, WP-CLI) and in Chromium
translations/ Greek translation (.po), for translate.wordpress.org
wporg-assets/ Icon, banner and screenshots for the WordPress.org page
docs/ User guide in Greek
CHANGELOG.md Changes per version

GitHub's Download ZIP and git archive contain only the plugin (.gitattributes leaves the rest out), but the folder from Download ZIP must be renamed to scrapelock before installing.

Build and checks

mkdir -p dist
git archive --format=zip --prefix=scrapelock/ -o dist/scrapelock-$(sed -n 's/^ \* Version: *//p' scrapelock.php).zip HEAD
phpcs                 # WordPress Coding Standards (phpcs.xml.dist)
cd tests && WP_DIR=/path/to/wordpress BASE=http://127.0.0.1:8099 ./run-all.sh

The same checks run on GitHub Actions for every pull request (.github/workflows/ci.yml). The plugin zip is kept as an artifact for 3 days, then deleted automatically. The plugin passes the official WordPress Plugin Check with no errors and no warnings.

To publish a release: Actions → Release → Run workflow on main, or push a version tag such as v2.8.2. .github/workflows/release.yml checks that the version matches Version, PNCP_VERSION and Stable tag, builds the zip and attaches it to the release.

Privacy

When a request is blocked, its IP address, User-Agent, page and time are logged and deleted automatically after 1, 7 or 30 days. Public IP lists (search engines, CDNs, AI search providers) are downloaded only when the related settings are on; no site or visitor data is sent anywhere. Details are in the "External services" section of readme.txt.

License

GPL-2.0-or-later © CodeBunny