{"id":343814,"date":"2026-08-18T22:22:17","date_gmt":"2026-08-18T22:22:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/surfacedby-ai-visibility\/"},"modified":"2026-08-18T22:22:03","modified_gmt":"2026-08-18T22:22:03","slug":"surfacedby-ai-visibility","status":"publish","type":"plugin","link":"https:\/\/test.wordpress.org\/plugins\/surfacedby-ai-visibility\/","author":23536329,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.6","stable_tag":"1.2.6","tested":"7.0.4","requires":"6.3","requires_php":"7.4","requires_plugins":null,"header_name":"SurfacedBy AI Visibility","header_author":"SurfacedBy","header_description":"Track AI bots, referrals, and conversions; check robots.txt, llms.txt, and schema; optionally sync to SurfacedBy.","assets_banners_color":"cce0fb","last_updated":"2026-08-18 22:22:03","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/surfacedby.com\/","header_author_uri":"https:\/\/surfacedby.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":38,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.6":{"tag":"1.2.6","author":"surfacedby","date":"2026-08-18 22:22:03"}},"upgrade_notice":{"1.2.6":"<p>Stops a rejected batch of events from being resent on every scheduled run.\nSafe update, nothing to set up.<\/p>","1.2.5":"<p>Corrects page credit for store purchases so the home page is no longer shown\nas the page that earned a sale. Safe update, nothing to set up.<\/p>","1.2.4":"<p>Fixes button label contrast in the WordPress admin. Safe update, nothing to\nset up.<\/p>","1.2.3":"<p>Hardens the local browser event route, removes direct database-driver access,\nand improves output escaping and privacy controls. Safe update, nothing to set\nup.<\/p>","1.2.1":"<p>Trials are tracked as their own conversion type, AI crawls of robots.txt and\nllms.txt are recorded, and bot identity is verified so spoofed crawlers are not\ncounted. Safe update, nothing to set up.<\/p>","1.2.0":"<p>More reliable AI visit tracking on cached sites, CDNs, and privacy-focused\nbrowsers, plus subscription renewals credited to the original AI source.\nSafe update, nothing to set up.<\/p>","1.1.0":"<p>Adds AI conversion tracking for WooCommerce and MemberPress, plus a\nwindow.sbAi.track JavaScript API for custom front-ends. Safe upgrade; no\ndata migration needed.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3653602,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3653602,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3653602,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3653602,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.6"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3653602,"resolution":"1","location":"assets","locale":"","width":1293,"height":1202},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3653602,"resolution":"2","location":"assets","locale":"","width":1293,"height":718},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3653602,"resolution":"3","location":"assets","locale":"","width":1293,"height":737},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3653602,"resolution":"4","location":"assets","locale":"","width":1293,"height":493},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3653602,"resolution":"5","location":"assets","locale":"","width":1293,"height":586},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3653602,"resolution":"6","location":"assets","locale":"","width":1293,"height":649}},"screenshots":{"1":"AI Bot Analytics dashboard","2":"AI Referrals by platform","3":"Readiness diagnostics","4":"llms.txt editor","5":"Schema scan results","6":"Connect a SurfacedBy Site ID"}},"plugin_section":[],"plugin_tags":[239387,236374,246076,244525,245227],"plugin_category":[],"plugin_contributors":[141250,276369],"plugin_business_model":[],"class_list":["post-343814","plugin","type-plugin","status-publish","hentry","plugin_tags-ai-analytics","plugin_tags-ai-seo","plugin_tags-ai-visibility","plugin_tags-answer-engine-optimization","plugin_tags-generative-engine-optimization","plugin_contributors-alikhallad","plugin_contributors-surfacedby","plugin_committers-surfacedby"],"banners":{"banner":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/banner-772x250.png?rev=3653602","banner_2x":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/banner-1544x500.png?rev=3653602","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/icon-128x128.png?rev=3653602","icon_2x":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/icon-256x256.png?rev=3653602","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-1.png?rev=3653602","caption":"AI Bot Analytics dashboard"},{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-2.png?rev=3653602","caption":"AI Referrals by platform"},{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-3.png?rev=3653602","caption":"Readiness diagnostics"},{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-4.png?rev=3653602","caption":"llms.txt editor"},{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-5.png?rev=3653602","caption":"Schema scan results"},{"src":"https:\/\/ps.w.org\/surfacedby-ai-visibility\/assets\/screenshot-6.png?rev=3653602","caption":"Connect a SurfacedBy Site ID"}],"raw_content":"<!--section=description-->\n<p>AI search is eating Google clicks. ChatGPT, Claude, Perplexity, and\nGemini answer questions inline now, and getting your site cited\ninside those answers is the new SEO. People call it\n<strong>Generative Engine Optimization (GEO)<\/strong> or <strong>Answer Engine\nOptimization (AEO)<\/strong>. Same problem either way: an AI has to crawl\nyou, parse you, and pick you when a user asks. Miss any of that and\nyou are invisible to the audience driving the next wave of traffic.<\/p>\n\n<p>SurfacedBy AI Visibility is the WordPress companion for that work.<\/p>\n\n<ul>\n<li><p><strong>AI Bot Analytics.<\/strong> Which AI crawlers are reading your site, what\nthey are after (training data, search indexing, or live retrieval),\nand how often. Covers GPTBot, ClaudeBot, PerplexityBot,\nMeta-ExternalAgent, and the long tail.<\/p><\/li>\n<li><p><strong>AI Referral Tracking.<\/strong> Real visits from chatgpt.com, claude.ai,\nperplexity.ai, gemini.google.com, copilot.microsoft.com, grok.com,\nand meta.ai. Proven referrer hosts only, no behavioural guessing.<\/p><\/li>\n<li><p><strong>AI Readiness Diagnostics.<\/strong> A one-click check on robots.txt,\nyour llms.txt, and the schema types answer engines look for\n(Organization, Article, FAQPage, Product). It tells you what is\nbroken.<\/p><\/li>\n<li><p><strong>llms.txt Generator.<\/strong> Publishes a clean <code>\/llms.txt<\/code> index of\nyour posts and pages so AI tools can find your content. Respects\nYoast, Rank Math, AIOSEO, and SEOPress noindex rules.<\/p><\/li>\n<li><p><strong>AI Conversion Tracking.<\/strong> Detects WooCommerce and MemberPress\nautomatically and credits purchases, renewals, signups, and refunds\nto the AI source that drove the customer. Custom checkouts call\n  window.sbAi.track()`` to ship the same data. Attribution holds\nfrom first visit through to purchase, even days later.<\/p><\/li>\n<\/ul>\n\n<p>All five are fully functional without an account. Bot logging,\nreferral tracking, the readiness diagnostics, the llms.txt generator,\nand conversion attribution all run locally on your server and store\ntheir data in your own database. Nothing is locked, time-limited, or\nreduced until you sign up, and the plugin does not talk to SurfacedBy\nat all until you pair it with a Site ID.<\/p>\n\n<p>Pairing is optional and adds one thing: it syncs the data this plugin\nalready collected to the SurfacedBy dashboard, where it sits next to\nthe AI ranking and citation analytics for your domain. Events recorded\nbefore you pair are synced too, so you do not lose the history. The\nfree plan covers one domain with weekly scans. Paid plans add\ncompetitor benchmarks, prompt tracking, and citation monitoring across\nChatGPT, Claude, Perplexity, and Gemini. Those run on SurfacedBy's\nservers and are not features withheld from this plugin.<\/p>\n\n<h3>External Services<\/h3>\n\n<p>The plugin makes no outbound calls until you save a SurfacedBy Site\nID under SurfacedBy &gt; Connect. If you never pair the plugin, nothing\nleaves your server, and every feature still works locally.<\/p>\n\n<p>Once paired, the plugin contacts SurfacedBy in three places (1-3). All\noutbound calls are made by your server; the plugin never loads or executes\ncode from an external source. Item 4 is listed for completeness because it\nis a browser-side feature, but it stays entirely on your own domain.<\/p>\n\n<ol>\n<li><p>Event forwarding (opportunistic on page-render shutdown, plus a wp-cron\nsafety net every hour):\nEndpoint: https:\/\/api.surfacedby.com\/api\/v1\/tracker\/batch\nData sent: rows from the local log tables. Three event kinds ship on the\nsame batch endpoint:<\/p>\n\n<ul>\n<li>bot rows: bot token, request path, hour of day, count, response\ncode, and bot-only requester IP for identity verification.<\/li>\n<li>referral rows: AI referrer host, request path, hour of day, count,\nsession nonce, and pseudonymous visitor ID.<\/li>\n<li>conversion rows (when WooCommerce \/ MemberPress is detected, or when\na custom front-end calls window.sbAi.track): event type\n(purchase \/ renewal \/ signup \/ refund \/ lead \/ custom), an order or\nsubscription identifier, the value, the ISO currency code, the request\npath, the AI referrer host that originally brought the customer in,\nand a small metadata object (item count, country code, refund reason,\netc., capped at 4 KB), plus the pseudonymous visitor ID when one is\navailable. Conversion rows never carry visitor names, emails, billing\naddresses, or payment details.\nThe plugin never sends raw User-Agent strings outside the bundled\nregistry, never sends human visitor IPs, and never sends cookies.\nMatched bot IPs are used by SurfacedBy only to compute a verified,\nunverified, or unverifiable bot-identity verdict; SurfacedBy stores\nthe verdict, not the raw IP. The local queue clears the bot IP after\nthe row forwards successfully.\nPurpose: populates your SurfacedBy dashboard for this site.<\/li>\n<\/ul><\/li>\n<li><p>Plugin heartbeat (hourly cron with a 24-hour staleness check, plus a\nbest-effort nudge when the plugin notices its last heartbeat is older\nthan 20 hours):\nEndpoint: https:\/\/api.surfacedby.com\/api\/v1\/integrations\/wordpress\/heartbeat\nData sent: your Site ID, plugin version, WordPress version, PHP version,\nand the aggregate event count from the last 24 hours. No personal data.\nPurpose: shows install health in the SurfacedBy admin.<\/p><\/li>\n<li><p>Bot registry refresh (daily cron with a 14-day staleness check; a\nconditional GET that returns 304 when nothing has changed):\nEndpoint: https:\/\/api.surfacedby.com\/api\/v1\/tracker\/registry (HTTP GET)\nData sent: none, other than standard HTTP request headers.\nPurpose: pulls the latest AI bot user-agent list so newly observed\ncrawlers are tracked without waiting for a plugin update.<\/p><\/li>\n<li><p>Browser tracker beacon (on by default; switch it off under \"Browser\ntracker snippet\" in Settings. It needs no account and runs whether or\nnot the plugin is paired):\nThis step sends nothing to SurfacedBy directly. The beacon script is\nbundled inside the plugin (assets\/js\/sb-tracker.js) and is served from\nyour own site; no external script is ever loaded, and no third-party\ncode is downloaded or executed. The script posts same-origin to this\nsite's own admin-ajax handler (admin-ajax.php). Each request carries a\nWordPress security nonce that the page includes, so the handler confirms\nthe request came from your own site before recording anything.\nData sent (to your own server): the AI referrer host, the URL path,\nand - when window.sbAi.track is called from custom front-end code -\nthe conversion event_id, value, currency, and a small metadata object\nthe site explicitly passes in. It also sends the plugin's pseudonymous\nvisitor ID. The plugin sets only the sb_t and sb_attr cookies described\nin the Cookies section below.\nThose rows are stored in the local log tables and later forwarded to\nSurfacedBy by the server, on the same batch endpoint described in\nitem 1 above.\nPurpose: catches AI referrals on pages served from a full-page cache\nwhere the PHP path never runs.<\/p><\/li>\n<\/ol>\n\n<h3>Cookies<\/h3>\n\n<p>The plugin sets cookies only after a visitor arrives from a confirmed AI\nreferrer host. Two cookies, both first-party, both opaque:<\/p>\n\n<ul>\n<li><code>sb_t<\/code> (30 minutes): an anonymous session nonce used to deduplicate\npage views inside one browsing session. No personal identifiers.<\/li>\n<li><code>sb_attr<\/code> (13 months): records a pseudonymous visitor ID, the AI host\n(e.g. chatgpt.com), and the timestamp of the first qualifying visit so a\nlater purchase or signup can be credited to the original source. When\npresent in an AI-attributed landing URL, it can also retain advertising\nclick IDs named gclid, fbclid, msclkid, and ttclid. The browser tracker\nmirrors this value in first-party local storage so attribution can survive\nbrowser cookie eviction. The identifier is scoped to this site and is not\nused for cross-site tracking.<\/li>\n<\/ul>\n\n<p>When paired with SurfacedBy, aggregate bot, referral, and conversion\nhistory is retained with the connected domain. Raw AI visit rows used\nfor dashboard journey reconstruction follow the server-side plan\nwindow: Free and Starter 90 days, Professional 395 days, Business 760\ndays. The dashboard journey drawer shows only the 30 days before a\nconversion.<\/p>\n\n<p>The referral cookies are set after a recognised AI referral. The conversion\nintegrations or a site-initiated window.sbAi.track call can also create the\npseudonymous sb_attr identifier when a conversion needs a stable local\nattribution key.<\/p>\n\n<p>Terms of Service: https:\/\/surfacedby.com\/terms\nPrivacy Policy: https:\/\/surfacedby.com\/privacy<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from the WordPress.org directory or upload the zip.<\/li>\n<li>Activate it.<\/li>\n<li>Visit SurfacedBy &gt; Dashboard in the WordPress admin.<\/li>\n<li>Run the AI Readiness checks; the local features start collecting bot\nand referral data immediately.<\/li>\n<li>Pair the plugin with SurfacedBy: sign in or create an account at\nsurfacedby.com, add your site, copy your Site ID, paste it into\nSurfacedBy &gt; Connect, and save. Your data starts syncing to the\ndashboard once verification completes.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20slow%20down%20my%20site%3F\"><h3>Does this plugin slow down my site?<\/h3><\/dt>\n<dd><p>No. Bot detection runs server-side before the response is sent and adds under\n10 ms per bot request. Normal human requests are untouched.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20track%20human%20visitors%3F\"><h3>Does this plugin track human visitors?<\/h3><\/dt>\n<dd><p>Referral tracking runs only when someone arrives from a confirmed AI tool.\nVisits from Google, social, or direct links are not logged as AI referrals.\nFor a qualifying visit, the plugin stores the referrer host, request path,\nevent time, a short session nonce, and a pseudonymous visitor ID. Enabled\ncommerce integrations and explicit window.sbAi.track calls can also record\nconversion details as described under External Services.<\/p><\/dd>\n<dt id=\"what%20does%20pairing%20the%20plugin%20with%20surfacedby%20give%20me%3F\"><h3>What does pairing the plugin with SurfacedBy give me?<\/h3><\/dt>\n<dd><p>Pairing pushes the data the plugin already captures (bots, referrals,\nconversions) up to the SurfacedBy dashboard, where it lines up next\nto the AI ranking and citation analytics for your domain. The local\nfeatures keep working the same way whether you pair or not.<\/p><\/dd>\n<dt id=\"what%20if%20i%20block%20ai%20bots%20in%20robots.txt%3F\"><h3>What if I block AI bots in robots.txt?<\/h3><\/dt>\n<dd><p>The plugin shows you which bots you are blocking and what that means\n(training, search indexing, or retrieval). You choose the policy. The plugin\nnever edits your robots.txt.<\/p><\/dd>\n<dt id=\"will%20the%20plugin%20work%20with%20my%20seo%20plugin%3F\"><h3>Will the plugin work with my SEO plugin?<\/h3><\/dt>\n<dd><p>Yes. Keep Yoast, Rank Math, AIOSEO, or SEOPress for Google rankings,\nand let SurfacedBy handle the AI side. The llms.txt generator reads\nnoindex and nofollow flags from your existing SEO plugin, so excluded\ncontent stays excluded.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20track%20woocommerce%20orders%20or%20memberpress%20signups%3F\"><h3>Does the plugin track WooCommerce orders or MemberPress signups?<\/h3><\/dt>\n<dd><p>Yes, automatically, with no shortcode or checkout edits. Activate\nWooCommerce or MemberPress and the plugin starts recording purchases,\nsubscription renewals, refunds, and signups against the AI source\nthat drove the customer. For non-WordPress checkouts (headless\nShopify, custom front-ends), call\n    window.sbAi.track('purchase', { event_id, value, currency })`` and\nthe data lands in the same place.<\/p><\/dd>\n<dt id=\"can%20i%20turn%20conversion%20tracking%20off%3F\"><h3>Can I turn conversion tracking off?<\/h3><\/dt>\n<dd><p>Yes. SurfacedBy &gt; Settings has a \"Track conversions\" toggle. Disabling it\nstops every adapter and the JS API at the source; nothing is logged or\nforwarded.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20easy%20digital%20downloads%3F\"><h3>Does it work with Easy Digital Downloads?<\/h3><\/dt>\n<dd><p>Yes. EDD is auto-detected the same way WooCommerce and MemberPress are.\nCompleted payments ship as purchases and refunds ship as separate\nnegative-value rows so partial refunds compose cleanly.<\/p><\/dd>\n<dt id=\"can%20i%20forward%20google%20tag%20manager%20purchases%20to%20surfacedby%3F\"><h3>Can I forward Google Tag Manager purchases to SurfacedBy?<\/h3><\/dt>\n<dd><p>Yes, with one toggle. Enable \"GTM bridge\" in SurfacedBy &gt; Settings and\nthe plugin subscribes to dataLayer <code>purchase<\/code> events and forwards them\nto <code>window.sbAi.track('purchase', ...)<\/code> using the raw GA4 transaction\nID. The dashboard's cross-source dedup pass collapses this row with the\nWooCommerce-adapter row keyed by the same order number, so a site\nrunning both does not double-count. The dedicated GTM tag template\n(integrations\/gtm-tag-template\/) is the more flexible option when you\nneed to forward refunds or custom event types.<\/p><\/dd>\n<dt id=\"can%20i%20send%20conversions%20from%20outside%20wordpress%20%28server-side%20webhook%29%3F\"><h3>Can I send conversions from outside WordPress (server-side webhook)?<\/h3><\/dt>\n<dd><p>Yes. SurfacedBy publishes a per-domain webhook URL plus an HMAC-SHA256\nshared secret that signs each delivery. Reveal the secret in the\nSurfacedBy dashboard's Tracking page Setup Drawer, then POST events\nto <code>https:\/\/api.surfacedby.com\/api\/v1\/tracker\/webhook\/conversions<\/code>\nwith the <code>X-SurfacedBy-Site-Id<\/code>, <code>X-SurfacedBy-Timestamp<\/code>, and\n    X-SurfacedBy-Signature: t=,v1=<code>headers. The signature\ncovers<\/code>.`` with HMAC-SHA256, matching the outbound\nSurfacedBy webhook scheme. Replay window is 5 minutes; the per-Site-ID\nrate limit is 100 requests \/ minute.<\/p>\n\n<p>Example curl:<\/p>\n\n<pre><code>curl -X POST https:\/\/api.surfacedby.com\/api\/v1\/tracker\/webhook\/conversions \\\\\n  -H \"X-SurfacedBy-Site-Id: SB-XXXXXXXXXXXX\" \\\\\n  -H \"X-SurfacedBy-Timestamp: 1715990400\" \\\\\n  -H \"X-SurfacedBy-Signature: t=1715990400,v1=&lt;hex&gt;\" \\\\\n  -H \"Content-Type: application\/json\" \\\\\n  -d '{\"event_type\":\"purchase\",\"event_id\":\"4821\",\"value\":99.99,\"currency\":\"USD\",\"occurred_at\":\"2026-05-18T12:00:00Z\"}'\n<\/code><\/pre><\/dd>\n<dt id=\"how%20does%20cross-source%20deduplication%20work%3F\"><h3>How does cross-source deduplication work?<\/h3><\/dt>\n<dd><p>If you wire multiple sources for the same site (this plugin plus the\nGTM bridge plus a server-side webhook), SurfacedBy automatically\ndeduplicates by event ID. The strongest source wins (plugin first,\nthen webhook, then JS), and the others appear in the dashboard as\n\"+ N sources\" on the surviving row. To make dedup most accurate, use\nthe order number as the event ID across every source so the underlying\nkeys line up.<\/p><\/dd>\n<dt id=\"can%20i%20add%20my%20own%20conversion%20adapter%3F\"><h3>Can I add my own conversion adapter?<\/h3><\/dt>\n<dd><p>Yes. Implement\n    \\SurfacedBy\\AIVisibility\\Conversion\\Adapters\\ConversionAdapter<code>and\nregister your class via the<\/code>surfacedby_aiv_conversion_adapters<code>filter. Adapters that expose an optional static<\/code>events_covered()``\nmethod will appear in the dashboard's coverage matrix.<\/p><\/dd>\n<dt id=\"can%20i%20point%20the%20plugin%20at%20a%20local%20surfacedby%20backend%20during%20development%3F\"><h3>Can I point the plugin at a local SurfacedBy backend during development?<\/h3><\/dt>\n<dd><p>Yes. Hook the <code>surfacedby_aiv_api_base<\/code> filter from a mu-plugin and\nreturn your local URL (for example <code>http:\/\/host.docker.internal:8000<\/code>)\nso the plugin sends events to your local backend instead of the\nproduction API. The filter applies to every HTTP call the plugin\nmakes, including heartbeat and event shipper.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.6<\/h4>\n\n<ul>\n<li>Changed: The browser tracker now sends its events through the WordPress\nhandler built for submissions from logged-out visitors. Tracking behaviour\nand the data recorded are unchanged.<\/li>\n<li>Fixed: Exported CSV files no longer let a recorded page address be treated\nas a formula by a spreadsheet application when the file is opened.<\/li>\n<li>Fixed: A tracking request carrying an unexpected value type is now ignored\ncleanly instead of adding a PHP warning to the site's error log.<\/li>\n<li>Fixed: When SurfacedBy rejects a batch of events, the plugin now reports\nthat and moves on instead of resending the same batch on every scheduled\nrun until it expires, which held up the events queued behind it.<\/li>\n<\/ul>\n\n<h4>1.2.5<\/h4>\n\n<ul>\n<li>Fixed: Purchases recorded from WooCommerce, Easy Digital Downloads, and\nMemberPress no longer report the home page as the page that earned the\nsale. These run after checkout, away from any page, so the sale is now\nrecorded without a page instead of being credited to the wrong one.<\/li>\n<li>Fixed: The top converting pages list no longer counts sales that have no\npage attached to them.<\/li>\n<\/ul>\n\n<h4>1.2.4<\/h4>\n\n<ul>\n<li>Fixed: Button labels remain readable in their normal, visited, hover,\nfocus, and active states throughout the WordPress admin.<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>Security: Browser event writes are gated by a WordPress nonce that is\nverified in the REST permission callback before the write runs.<\/li>\n<li>Security: Duplicate conversion detection now uses a prepared WordPress\ndatabase query instead of inspecting the database driver directly.<\/li>\n<li>Fixed: Admin icons and generated markup are escaped at output time using a\nnarrow SVG allow-list.<\/li>\n<li>Improved: Plugin-owned cache keys use the full surfacedby_aiv prefix.<\/li>\n<li>Improved: Privacy disclosures now describe pseudonymous identifiers,\nlocal storage, advertising click IDs, and individual event forwarding.\nLogged-in attribution can be exported and erased with WordPress privacy\ntools.<\/li>\n<li>Compatibility: No settings changes or data migration are required.<\/li>\n<li>Compatibility: Tested with WordPress 7.0.2.<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Changed: The browser tracker no longer requires a SurfacedBy account. It\nrecords AI referrals and conversions into your own database on a fresh\ninstall, with no Site ID and no pairing. Connecting an account only syncs\nthat data to the dashboard.<\/li>\n<li>New: Events captured before you connect are kept and sync automatically\nonce you do, so pairing an existing install does not start from zero.<\/li>\n<li>New: Settings shows how many events are stored locally and waiting to\nsync.<\/li>\n<li>Fixed: Conversion logs were never pruned by the retention cron, so the\ntable grew without bound on sites that kept their data local.<\/li>\n<li>Fixed: A commerce integration that declared its event list as a\nnon-static method caused a fatal error when the plugin read it.<\/li>\n<li>Hardened: Cookie, header, and server values are sanitised on read, and\nthe referrer host recovered from the attribution cookie is validated as\na hostname before it is stored or forwarded.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>New: Trials are a first-class conversion type, so a trial start, its\nconversion to paid, later renewals, and refunds each show up separately\ninstead of collapsing into one purchase.<\/li>\n<li>New: Bot identity verification. A request claiming to be an AI crawler is\nchecked against the bot's published address ranges, so spoofed traffic is\nnot counted as a real AI bot.<\/li>\n<li>Improved: AI crawls of <code>robots.txt<\/code> and <code>llms.txt<\/code> are now recorded, so\nyou can see which crawlers are reading your AI access rules.<\/li>\n<li>Improved: The attribution cookie is capped at 13 months from the first time\nit was set.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Improved: AI visits are now tracked reliably on sites that use caching\nor a CDN such as Cloudflare. This works automatically; you can turn it\noff under Settings if you ever need to.<\/li>\n<li>Improved: AI visits are still matched to the sale on browsers with\nstrict privacy settings, such as Safari, so your conversion reports\nstay accurate.<\/li>\n<li>Improved: Subscription renewals are now credited to the AI source that\nwon the original sale, so recurring revenue keeps showing up in your AI\nreports for the life of the subscription.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New: AI conversion tracking. Auto-detects WooCommerce and MemberPress and\nrecords purchases, renewals, signups, and refunds against the AI source\nthat brought the customer in.<\/li>\n<li>New: <code>window.sbAi.track()<\/code> JavaScript API for custom front-ends and\nnon-WordPress checkouts (Shopify Hydrogen, headless storefronts).<\/li>\n<li>New: <code>sb_attr<\/code> attribution cookie so conversions are credited\nto the AI platform even days after the original visit.<\/li>\n<li>New: Conversions admin tab with 7-day totals, by-type breakdown, and a\nrecent-activity table; only shown when at least one supported platform\nis detected.<\/li>\n<li>New: Adapter registry (<code>surfacedby_aiv_conversion_adapters<\/code> filter)\nfor downstream plugins that want to register additional adapters\nwithout forking.<\/li>\n<li>Improved: Event shipper now drains conversion rows alongside bot and\nreferral rows on the same hourly cron + page-render shutdown path.<\/li>\n<li>Improved: Idempotent end-to-end ingest. Rows are deduplicated on a\nstable event_id so a re-fired purchase or replayed webhook is a no-op.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Server-side analytics for AI traffic: see which AI bots crawl you, which AI assistants send visitors, and which of those visits become sales.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/343814","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=343814"}],"author":[{"embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/surfacedby"}],"wp:attachment":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=343814"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=343814"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=343814"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=343814"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=343814"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=343814"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}