{"id":362135,"date":"2026-10-09T05:17:18","date_gmt":"2026-10-09T05:17:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/anonage-age-verification\/"},"modified":"2026-10-09T05:17:04","modified_gmt":"2026-10-09T05:17:04","slug":"anonage-age-verification","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/anonage-age-verification\/","author":518316,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.6.1","stable_tag":"0.6.1","tested":"7.1.3","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"AnonAge Age Verification","header_author":"AnonAge","header_description":"Put an age gate over your site. Self-declaration that needs no account, no API key and no outbound requests, with three levels of enforcement.","assets_banners_color":"06122b","last_updated":"2026-10-09 05:17:04","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/docs.anonage.io\/plugins\/wordpress","header_author_uri":"https:\/\/anonage.io\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":44,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.6.1":{"tag":"0.6.1","author":"cclambie","date":"2026-10-09 05:17:04","revision":3735928}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3735928,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3735928,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3735928,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3735928,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.6.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3735928,"resolution":"1","location":"assets","locale":"","width":1600,"height":1748},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3735928,"resolution":"10","location":"assets","locale":"","width":1600,"height":1200},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3735928,"resolution":"2","location":"assets","locale":"","width":1200,"height":1228},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3735928,"resolution":"3","location":"assets","locale":"","width":1200,"height":1228},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3735928,"resolution":"4","location":"assets","locale":"","width":1200,"height":1228},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3735928,"resolution":"5","location":"assets","locale":"","width":1200,"height":1228},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3735928,"resolution":"6","location":"assets","locale":"","width":1200,"height":1228},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3735928,"resolution":"7","location":"assets","locale":"","width":1600,"height":1292},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3735928,"resolution":"8","location":"assets","locale":"","width":1600,"height":1200},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3735928,"resolution":"9","location":"assets","locale":"","width":1600,"height":1200}},"screenshots":{"1":"The Gate tab: how the age is checked, how much of the page is withheld, and what the gate applies to.","2":"The gate as a visitor sees it, over a page they have not passed.","3":"The same page once they have.","4":"The proof that \"Hide the restricted part\" is not just an overlay \u2014 with the gate's own element deleted in developer tools, the restricted content is still not there.","5":"Verified mode (coming soon, not yet available): a QR code the visitor scans with the AnonAge app. Nothing but a session reference is in the code.","6":"Placing the split with the <code>[anonage_gate]<\/code> block. Everything above it stays public and indexable.","7":"Appearance: colours, logo, background image and corner radius.","8":"Content: every string in the panel is yours to rewrite.","9":"Connection (for verified mode, coming soon): the API key, and a live check that the callback can reach your site.","10":"Advanced: excluded roles and URLs, how long a visitor stays through the gate, and debug logging."}},"plugin_section":[],"plugin_tags":[70877,41695,5616,14361,285233],"plugin_category":[],"plugin_contributors":[90676],"plugin_business_model":[],"class_list":["post-362135","plugin","type-plugin","status-publish","hentry","plugin_tags-age-gate","plugin_tags-age-restriction","plugin_tags-age-verification","plugin_tags-compliance","plugin_tags-online-safety-act","plugin_contributors-cclambie","plugin_committers-cclambie"],"banners":{"banner":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/banner-772x250.png?rev=3735928","banner_2x":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/banner-1544x500.png?rev=3735928","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/icon-128x128.png?rev=3735928","icon_2x":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/icon-256x256.png?rev=3735928","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-1.png?rev=3735928","caption":"The Gate tab: how the age is checked, how much of the page is withheld, and what the gate applies to."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-2.png?rev=3735928","caption":"The gate as a visitor sees it, over a page they have not passed."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-3.png?rev=3735928","caption":"The same page once they have."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-4.png?rev=3735928","caption":"The proof that \"Hide the restricted part\" is not just an overlay \u2014 with the gate's own element deleted in developer tools, the restricted content is still not there."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-5.png?rev=3735928","caption":"Verified mode (coming soon, not yet available): a QR code the visitor scans with the AnonAge app. Nothing but a session reference is in the code."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-6.png?rev=3735928","caption":"Placing the split with the <code>[anonage_gate]<\/code> block. Everything above it stays public and indexable."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-7.png?rev=3735928","caption":"Appearance: colours, logo, background image and corner radius."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-8.png?rev=3735928","caption":"Content: every string in the panel is yours to rewrite."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-9.png?rev=3735928","caption":"Connection (for verified mode, coming soon): the API key, and a live check that the callback can reach your site."},{"src":"https:\/\/ps.w.org\/anonage-age-verification\/assets\/screenshot-10.png?rev=3735928","caption":"Advanced: excluded roles and URLs, how long a visitor stays through the gate, and debug logging."}],"raw_content":"<!--section=description-->\n<p>AnonAge Age Verification puts an age gate in front of your content. It works out of the box with no\naccount, no API key and no cost.<\/p>\n\n<p><strong>Two free self-declaration modes<\/strong><\/p>\n\n<ul>\n<li><strong>Confirm<\/strong> \u2014 the visitor clicks \"I am over 18\" (or 13, 16, 21).<\/li>\n<li><strong>Year of birth<\/strong> \u2014 the visitor enters their year of birth. They are only asked for the month, and\nthen the day, when the year alone does not settle it. Most people answer one question.<\/li>\n<\/ul>\n\n<p><strong>Three levels of enforcement<\/strong><\/p>\n\n<ul>\n<li><strong>Cover the page<\/strong> \u2014 the gate is drawn over the content in the browser. Cache-friendly and\nkeeps the page fully indexable, but it is advisory: a visitor can remove it with developer\ntools, or by turning JavaScript off. Fine as a courtesy notice; it is not a lock.<\/li>\n<li><strong>Hide the restricted part<\/strong> (recommended) \u2014 the page still loads and is still found by search\nengines. Everything below a marker you place never leaves your server until the visitor has\nproved their age. Works under any page cache with nothing to configure, because the page sent\nto every visitor is identical.<\/li>\n<li><strong>Withhold the whole page<\/strong> \u2014 nothing but the gate is sent. The strongest option, and the right\none for a page with nothing safe to show, but search engines see only the gate.<\/li>\n<\/ul>\n\n<p><strong>Built for real WordPress sites<\/strong><\/p>\n\n<ul>\n<li><strong>Works with your cache plugin.<\/strong> The gate is applied in the browser, so the HTML served to every\nvisitor is identical. Nothing to configure in WP Rocket, LiteSpeed, W3TC or Cloudflare.<\/li>\n<li><strong>No flash of gated content.<\/strong> The cover is painted from <code>&lt;head&gt;<\/code> before the page renders, not\nafter everything has already appeared on screen.<\/li>\n<li><strong>Administrators are never gated<\/strong> by default, so you can still edit your site.<\/li>\n<li>Gate the whole site, selected pages (ticking a parent covers its children), or everything under\na URL path such as <code>\/gated\/<\/code>. Set how long a visitor stays through the gate, exclude URLs and\nroles, and restyle every part of the panel.<\/li>\n<li><strong>Membership sites<\/strong>: for a logged-in visitor the result is recorded against their account, so\nthey verify once rather than once per device. Fires <code>anonage_member_verified<\/code> for your own\nrecords.<\/li>\n<li>No third-party requests. No tracking. Nothing is loaded from anyone else's server.<\/li>\n<\/ul>\n\n<p><strong>Verified mode \u2014 not in this release<\/strong><\/p>\n\n<p>Self-declaration is honest about what it is: anyone can click a button. Verified mode checks the\nvisitor's age against a real identity check through the AnonAge app \u2014 they scan a QR code, or tap\nthrough on a phone, and your site receives a yes or no. You never see their documents, their name\nor their date of birth. That is the mode that meets \"highly effective age assurance\" style\nrequirements.<\/p>\n\n<p><strong>It is not enabled in this version.<\/strong> The code is here and the option is visible in the settings,\nmarked as arriving in a later release, so that nothing about your gate changes when it does. It is\nswitched off rather than left selectable because a mode that appears to check identity and does not\nis worse than one that is plainly unavailable. Everything described above this line works today and\nalways will, with no account.<\/p>\n\n<p>When it arrives it will need an AnonAge account and a paid plan. There is no free live tier: an\naccount costs a one-time \u00a32 set-up fee for the identity check on your own account, and then from\n\u00a32 a month, which includes 10,000 verifications. Up to 50,000 a month is \u00a35, and beyond that\n\u00a32.50 per additional 50,000 \u2014 so 200,000 a month is \u00a312.50 and a million is \u00a352.50. USD\nand EUR are charged at the same numbers rather than converted. Test keys are free and are never\ncounted against any of it. Billing follows usage, with no manual plan changes, and you can set a\nmonthly cap and warning thresholds so a spike is not a surprise invoice.<\/p>\n\n<ul>\n<li>Your secret key never leaves your server. The QR code carries only an opaque session reference.<\/li>\n<li>Results arrive over an HMAC-signed callback that is verified against the raw request body, with\na timestamp window so an old result cannot be replayed.<\/li>\n<li>If your site cannot receive inbound requests \u2014 a firewall, a staging domain, localhost \u2014 the\nplugin asks AnonAge for the result instead, so verification still completes.<\/li>\n<li>The QR code is generated on your own server. Nothing is sent to a third-party image service.<\/li>\n<\/ul>\n\n<h3>Is this \"highly effective age assurance\"?<\/h3>\n\n<p>It depends on two independent choices, and both have to be right.<\/p>\n\n<p><strong>How the age is checked.<\/strong> Self-declaration is a statement by the visitor, not a check \u2014 anyone\ncan click a button or type a year. It is what most sites run and it is a reasonable default, but\nit is not highly effective age assurance. Verified mode, which checks against a real identity\ncheck, is.<\/p>\n\n<p><strong>How the content is protected.<\/strong> \"Cover the page\" delivers the content and hides it in the\nbrowser, so it can be recovered with developer tools. \"Hide the restricted part\" and \"Withhold the\nwhole page\" do not deliver it at all.<\/p>\n\n<p>Getting one right and not the other achieves nothing: a real identity check behind a removable\noverlay still lets a child read the page. The settings screen warns you if you configure that\ncombination.<\/p>\n\n<h3>External services<\/h3>\n\n<p>The free self-declaration modes make <strong>no external requests at all<\/strong>. Nothing leaves your server.<\/p>\n\n<p>Verified mode communicates with the AnonAge API at <code>https:\/\/api.anonage.io<\/code> to open a verification\nsession and receive its result. Your secret API key stays on your server and is never sent to the\nbrowser. The data exchanged is a session identifier, a one-time nonce and a yes\/no answer \u2014 no\npersonal data about your visitor is sent to us or returned to you.<\/p>\n\n<ul>\n<li>Terms: https:\/\/anonage.io\/terms<\/li>\n<li>Privacy policy: https:\/\/anonage.io\/privacy<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to <code>\/wp-content\/plugins\/<\/code> or install it from the Plugins screen.<\/li>\n<li>Activate it.<\/li>\n<li>Go to <strong>Settings \u2192 AnonAge<\/strong>, choose a mode and a minimum age, and save.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20an%20anonage%20account%3F\"><h3>Do I need an AnonAge account?<\/h3><\/dt>\n<dd><p>No. Everything in this release \u2014 both self-declaration modes, all three enforcement levels, all of\nthe appearance and targeting options \u2014 is free, needs no account and makes no outbound requests of\nany kind. Nothing about your gate depends on us being reachable.<\/p>\n\n<p>An account and a paid plan are only needed for verified mode, which is not enabled in this release.<\/p><\/dd>\n<dt id=\"what%20will%20verified%20mode%20cost%3F\"><h3>What will verified mode cost?<\/h3><\/dt>\n<dd><p>There is no free live tier, and we would rather say so plainly than have you find out at the point\nof switching it on. A one-time \u00a32 set-up fee covers the identity check on your own account, then\nfrom \u00a32 a month including 10,000 verifications; \u00a35 a month up to 50,000; and \u00a32.50 per\nadditional 50,000 after that, so 200,000 a month is \u00a312.50 and a million is \u00a352.50. The same\nnumbers are charged in USD and EUR rather than being converted. Test keys are free and never\ncounted, so you can build and test the whole integration before paying anything.<\/p>\n\n<p>The visitor pays a small fee for their own identity check as well. Between the two, that is what\nfunds the service \u2014 rather than us making money from data about your visitors.<\/p><\/dd>\n<dt id=\"will%20this%20break%20my%20page%20cache%3F\"><h3>Will this break my page cache?<\/h3><\/dt>\n<dd><p>With \"Cover the page\" or \"Hide the restricted part\", no, and there is nothing to configure. The\npage sent to every visitor is identical \u2014 the gate is applied in the browser, and in split mode\nthe restricted content is fetched separately over a request that is never cached. Do not add the\n    anonage_verified cookie to any \"vary cache on this cookie\" list; it would fragment your cache\nfor no benefit.<\/p>\n\n<p>\"Withhold the whole page\" is the exception. That decision has to be made per visitor, so PHP has\nto run \u2014 and on a cache hit it does not. The plugin therefore marks every gated page as\nuncacheable, which WP Rocket, W3 Total Cache, WP Super Cache and LiteSpeed all honour\nautomatically. If you have a CDN in front of your site, including Cloudflare, add your own rule\nto bypass the cache on those URLs.<\/p><\/dd>\n<dt id=\"will%20it%20hide%20my%20site%20from%20google%3F\"><h3>Will it hide my site from Google?<\/h3><\/dt>\n<dd><p>That depends on which enforcement level you choose, and it is the main thing to think about.<\/p>\n\n<p>\"Cover the page\" changes nothing \u2014 the content is delivered in full and indexed as normal.<\/p>\n\n<p>\"Hide the restricted part\" is the balance most sites want: the page, its title, its description and\neverything you place above the marker stay indexable, while the restricted part is withheld. Put\nyour descriptive, keyword-carrying copy above the gate and it does the SEO work for the page.<\/p>\n\n<p>\"Withhold the whole page\" does hide those URLs from search engines, because the crawler receives\nthe gate and nothing else. Use it only on pages with nothing safe to show, and keep your landing\nand category pages ungated so the site stays findable.<\/p>\n\n<p>There is no way to withhold content from visitors and still have that content indexed. Serving\nsearch engines something visitors do not get is cloaking, and it is penalised. This plugin does not\ndo it.<\/p><\/dd>\n<dt id=\"can%20someone%20bypass%20it%3F\"><h3>Can someone bypass it?<\/h3><\/dt>\n<dd><p>With \"Cover the page\", yes \u2014 developer tools will remove any overlay, on any site, from any\nplugin, and turning JavaScript off stops the overlay existing at all. That level is advisory by\ndesign and is labelled as such.<\/p>\n\n<p>With \"Hide the restricted part\" or \"Withhold the whole page\", no: the content is not in the page\nat all, so there is nothing in the browser to reveal. The server checks a signed cookie in PHP\nbefore releasing it.<\/p>\n\n<p>If you are relying on this for a legal obligation, pair verified mode with one of those two \u2014 a\nreal age check behind an overlay anyone can dismiss enforces nothing.<\/p><\/dd>\n<dt id=\"what%20does%20it%20store%20about%20my%20visitors%3F\"><h3>What does it store about my visitors?<\/h3><\/dt>\n<dd><p>One cookie, <code>anonage_verified<\/code>, holding the age threshold they cleared and when it expires. It is\nsigned with your site's own key so it cannot be forged. No personal data, no analytics, no tracking.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.6.1<\/h4>\n\n<ul>\n<li>All CSS and JavaScript now goes through the WordPress asset APIs. The gate's cover has to be\ninline \u2014 it carries the site owner's own colours and has to be in place before the page paints \u2014\nbut it is now attached to registered handles with wp_add_inline_style() and wp_add_inline_script()\ninstead of being printed as tags, and the block-mode page's stylesheet moved into the enqueued\nfile. No <\/li>\n<li>The page-tree indentation on the settings screen is a class rather than an inline style, so the\nwhole admin screen's CSS lives in the enqueued stylesheet.<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li>Verified mode is explicitly unavailable in this release rather than selectable. It was gated on a\ncheck that could never fail, so it could be switched on against an API that is not yet in\nproduction \u2014 a mode that looks like it checks identity and does not is worse than one that is\nplainly marked as coming later.<\/li>\n<li>Documented what verified mode will cost when it arrives, including that there is no free live\ntier, so nobody discovers the price at the point of switching it on.<\/li>\n<li>Corrected the description: it advertised verified age checks as though they were available today.<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Tested against WordPress 7.0.<\/li>\n<li>Housekeeping for the plugin directory review: no behavioural changes.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Server-side enforcement. \"Hide the restricted part\" withholds everything below a marker until a\nsigned cookie is verified in PHP, while keeping the page indexable and cache-safe; \"Withhold the\nwhole page\" sends nothing but the gate and marks the page uncacheable.<\/li>\n<li>Target the gate at a URL path, and ticking a parent page now covers its children. The page\npicker shows the hierarchy and marks what is covered by inheritance.<\/li>\n<li>Membership sites: a logged-in visitor's verification is stored against their account, so it\ncarries across devices. New <code>anonage_member_verified<\/code> action.<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Appearance: gate background image with cover, contain, tile and centre fits, over a fallback\ncolour that shows while the image loads.<\/li>\n<li>Content: separate wording for the verify button and the QR instruction.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Verified mode: sessions opened server-side, an on-server QR generator, mobile deeplink,\nHMAC-signed result callback, status polling and a poll fallback for sites that cannot receive\ninbound requests.<\/li>\n<li>Per-visitor cap on session creation so a script cannot burn a site's verification allowance.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>First release: self-declaration modes (confirm, and year of birth), settings screen, appearance\nand content customisation, page\/URL\/role targeting, cache-safe client-side gating.<\/li>\n<\/ul>","raw_excerpt":"Put an age gate over your site. Self-declaration that needs no account, no API key and no outbound requests, with three levels of enforcement.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/362135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=362135"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/cclambie"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=362135"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=362135"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=362135"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=362135"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=362135"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=362135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}