cd /news/ai-tools/show-hn-see-when-chatgpt-or-perplexi… · home topics ai-tools article
[ARTICLE · art-51328] src=github.com ↗ pub= topic=ai-tools verified=true sentiment=↑ positive

Show HN: See when ChatGPT or Perplexity sends a visitor to your site

A new free tool called AI Referral Notifier runs as a Cloudflare Worker to send push notifications when AI assistants like ChatGPT or Perplexity send a visitor to a site, or when AI crawlers fetch pages. The tool detects referrals and crawlers at the edge without slowing the site, making visible which AI engines drive traffic.

read17 min views1 publishedJul 8, 2026
Show HN: See when ChatGPT or Perplexity sends a visitor to your site
Image: source

Get a push notification the moment an AI assistant sends you a real visitor: a person who clicked through from a ChatGPT, Perplexity, Gemini, Claude, Copilot, or Grok answer. A visitor an AI actively pointed at you is rare and high-value, and this tells you the instant it happens.

It can also alert on AI crawlers fetching your pages (to train on them, index them, or answer a user live). That is the far higher-volume signal: a busy site sees thousands of crawler hits a day. One setting, ALERT_ON

, chooses which signals fire (referrals

, crawlers

, or both

); it defaults to referrals because crawlers are so much noisier. Turn them on with

ALERT_ON=crawlers

or both

.It runs as a single Cloudflare Worker in front of your site, inspects each request at the edge, fires a notification to your phone, and passes the request straight through to your origin. No tracking script, no database, no change to your pages. Detection and notifications run off the response path, so your site is never slowed down.

Most "AI bot" tools are about blocking. But the AI crawl is not the threat, it is the tell: it is the clearest early signal of who is reading you and why. The interesting question is not "how do I keep AI bots out," it is "which AI engines actually touch me, and which ones send me people." This tool makes that visible in real time, for free.

This tool (free) tells you It cannot tell you
A human landed on your site from an AI assistant, and on which page Whether the AI actually cited you in an answer
An AI crawler hit your site, which vendor, and its purpose (train / index / answer live) Which prompts you show up for, and which you are missing
The visitor's country, real-time, at your edge Whether the AI recommended a competitor instead of you
Which signals to be alerted on (referrals, crawlers, or both) Whether that visibility turned into signups or revenue

The right-hand column is the actual job of AI visibility, and it needs measurement across the assistants, not just your own logs. This tool is the free first look at what reaches your edge.

You need a site that is already on Cloudflare (its traffic is proxied by Cloudflare, the orange cloud in your DNS).

First, pick a notification channel. The zero-account option is ntfy: install the ntfy app on your phone, tap Subscribe to topic, and enter a long, hard-to-guess topic name (treat it like a password, for example ai-alerts-9f3k2p-mysite

). That topic name is all you need. Prefer Telegram, WhatsApp, Discord, or Pushover? See Notification channels.

Then get the Worker deployed one of three ways:

+wrangler

, the most reliable path for developers.

After the first two, do the one-time Configure the Worker step.

Fork this repo, then let Cloudflare import your fork and deploy it. Forking is what makes this reliable: Cloudflare deploys straight from a repo you already own, so there is no create-repo step to fail, and every later change you make auto-deploys.

Fork this repository to your own GitHub account (theFork button, top right of the repo page).- In the Cloudflare dashboard, openWorkers & Pages and clickCreate application. - Click Continue with GitHub and authorize the Cloudflare GitHub app to access your fork when prompted. - Select your fork from the repository list and click Next. - Accept the defaults and click Deploy. Cloudflare readswrangler.toml

, soALERT_ON

(referrals) andCRAWLER_THROTTLE_SECONDS

are already filled in and the deploy command isnpx wrangler deploy

.You do not need to open Advanced settings- ignore the non-production-branch build command, the build token, and any "token is missing permissions" notice. None of it matters here. - Now do Configure the Worker: this deploy runs, but it will not alert anyone until you add a notification channel and a route.

Fallback: Clone a public repository via Git URL. On Ship something new you can instead click Clone a public repository via Git URL and paste https://github.com/surfacedby/ai-traffic-alerts-for-cloudflare.git

. This asks Cloudflare to create a fresh copy of the repo in your account, which can return HTTP 400 at the Deploy step (before any build runs) if the Cloudflare GitHub App lacks permission to create a repo (it is installed with "Only select repositories") or a repo of that name already exists. Forking first, as above, avoids this.

Create the Worker. In theCloudflare dashboard, go toCompute (Workers) -> Workers & Pages -> Create -> Start with Hello World -> Get started. Give it a name likeai-traffic-alerts

and create it.Paste the code. ClickEdit code(the</>

button). Select all of the sample code and delete it, then paste the entire contents of(open the link, select all, copy). Clicksrc/worker.js

Deploy.- Now do Configure the Worker.

The tool does not auto-pick where alerts go - it cannot know your phone or chat - so setting one notification channel is the single required step. Without it the Worker runs but stays silent (and logs "no notification channel is configured"). You do this in the Worker's own Settings after deploy; you do not need the wizard's Advanced settings.

Notification channel (required).**Variables and Secrets -> Add your channel values andset the Type to Secret**(not Text) for every one of them:NTFY_TOPIC

for ntfy, and likewise the Telegram, WhatsApp, Pushover, Discord, and generic-webhook values (seeNotification channelsfor exact names). On the Deploy-from-GitHub path this is not optional forany of them: a Git-connected Worker rebuilds fromwrangler.toml

on every deploy and treats its[vars]

as the complete set, so any plaintext dashboard variable issilently wiped on the next build- the Worker then still detects traffic and sends nothing, while Settings still shows the (now-empty) variable. Secrets are stored separately and survive builds. Set as many channels as you want - it alerts on all of them.What to alert on. AddALERT_ON

set toreferrals

,crawlers

, orboth

. Itdefaults to(the rare, high-value signal, and it needs no KV), so you can even skip this. Turn on the noisy crawler signal only if you want it.referrals

**Put it in front of your site.**Domains & Routes -> Add -> Route, patternyourdomain.com/*

, your zone. ChooseRoute, notCustom domain: a route runs the Worker on your existing site and passes traffic through to it.(Only if you set Create a KV namespace underALERT_ON

tocrawlers

orboth

) throttle crawlers.Storage & Databases -> KV -> Create a namespace, name itRADAR_KV

, then bind it in the Worker underSettings -> Bindings -> Add binding -> KV namespace with theVariable nameRADAR_KV

. It dedupes crawler alerts to one per vendor per purpose per hour.referrals

mode never touches KV.

That is it. See Test that it works to confirm.

The most reliable path if you are comfortable in a terminal: it deploys directly to your account, with no GitHub-App repo-creation step that can fail. You need Node and npx

.

git clone https://github.com/surfacedby/ai-traffic-alerts-for-cloudflare
cd ai-traffic-alerts-for-cloudflare
npm install

Set your channel, route, and what to alert on inwrangler.toml

:

routes = [ { pattern = "yourdomain.com/*", zone_name = "yourdomain.com" } ]

[vars]
ALERT_ON = "referrals"   # referrals | crawlers | both (default referrals)
NTFY_TOPIC = "your-long-secret-topic"

(Only if you alert on crawlers) create the throttle KV and paste the returned id into the[[kv_namespaces]]

block inwrangler.toml

. Inreferrals

mode you can skip this:

npx wrangler kv namespace create RADAR_KV

Deploy:

npx wrangler deploy

Run npm test

to exercise the detection logic, and npx wrangler tail

to watch live logs.

Set any one (or several). The Worker sends to every channel you configure. Each has a step-by-step guide below the table.

Channel What to set Guide
ntfy
NTFY_TOPIC (and optional NTFY_SERVER )

TelegramTELEGRAM_BOT_TOKEN

, TELEGRAM_CHAT_ID

Telegram setupWHATSAPP_PHONE

, WHATSAPP_APIKEY

WhatsApp setup- free personal alerts via CallMeBotDiscordDISCORD_WEBHOOK_URL

Discord setupPushoverPUSHOVER_TOKEN

, PUSHOVER_USER

Pushover setupAnything elseGENERIC_WEBHOOK_URL

Generic webhook- Slack, Zapier, your APIEvery channel is fire-and-forget with a 10-second timeout and checks the response, so one slow or misconfigured channel can neither delay the others nor break the request being served. Failures are logged with the channel name and HTTP status so you can see exactly what went wrong.

Where to put the values: NTFY_TOPIC

and every channel token are Secrets, never plaintext. NTFY_TOPIC

behaves like a password (anyone who knows the topic can read your alerts), and this repo is public, so it must never live in wrangler.toml

. In the dashboard, open the Worker's Settings -> Variables and Secrets -> Add and choose Type: Secret. On the command line, use npx wrangler secret put NAME

. Only non-sensitive settings (ALERT_ON

, CRAWLER_THROTTLE_SECONDS

, and the optional SITE_DOMAIN

/ NTFY_SERVER

) belong in wrangler.toml

. On a Git-connected (Builds) Worker, a plaintext variable added only in the dashboard is wiped on the next build; a Secret is not.

  • Install the ntfy app (iOS/Android), or openntfy.shin a browser. - Tap Subscribe to topic and enter a long, hard-to-guess name (anyone who knows the topic can see your alerts, so treat it like a password, for exampleai-alerts-9f3k2p-mysite

). - Set NTFY_TOPIC

to that exact name. Self-hosting ntfy? Also setNTFY_SERVER

(defaults tohttps://ntfy.sh

).

ntfy.sh free-tier quota. The free ntfy.sh

server caps how many messages you can publish per day, and that limit is per publishing IP. The Worker publishes from Cloudflare's shared egress IPs, so the quota can be reached faster than expected, especially with heavy testing or with ALERT_ON

set to crawlers

or both

(thousands of hits a day will exhaust it quickly). Free ntfy is fine for the rare referrals

signal; for crawler mode or any real volume, use a per-account channel (Telegram, Discord, or Pushover), or self-host ntfy and point NTFY_SERVER

at it. When the quota is hit, publishing returns HTTP 429 (see Troubleshooting) and resets daily.

, and follow the prompts. It gives you abot token like123456:ABC-DEF...

-> that isTELEGRAM_BOT_TOKEN

. - Open a chat with your new bot and send it any message (bots cannot message you until you message them first).

  • Get your chat id: openhttps://api.telegram.org/bot<YOUR_TOKEN>/getUpdates

in a browser (paste your token in). Find"chat":{"id":...}

in the JSON -> that number isTELEGRAM_CHAT_ID

. - Set both as secrets.

This uses CallMeBot, a free relay that messages your own number (it is personal-use only, which is exactly right for alerts to yourself).

  • Save the CallMeBot number +34 644 91 96 80 to your phone contacts. - From WhatsApp, send it exactly: I allow callmebot to send me messages

. Within a minute it replies with yourAPI key. - Set WHATSAPP_PHONE

to your number with country code (for example+15551234567

) andWHATSAPP_APIKEY

to the key it sent.

Sending to customers (not yourself) is a different problem: it needs Meta's WhatsApp Cloud API with a pre-approved message template, because an alert is a business-initiated message. For that, point GENERIC_WEBHOOK_URL

(below) at your Cloud API relay instead.

  • In your Discord server, open Server Settings -> Integrations -> Webhooks -> New Webhook(or a channel's** Edit Channel -> Integrations -> Webhooks**). - Choose the channel that should receive alerts, then click Copy Webhook URL. - Set DISCORD_WEBHOOK_URL

to that URL.

  • Create an account at pushover.netand install the Pushover app on your phone (one-time purchase after a trial). - Your User Key is on the dashboard home -> that isPUSHOVER_USER

. - Create an application token at pushover.net/apps/build(name it "AI traffic alerts") -> theAPI Token isPUSHOVER_TOKEN

. - Set both as secrets.

Set GENERIC_WEBHOOK_URL

to any endpoint and the Worker POSTs the event as JSON. The payload carries a ready-to-display text

field plus structured fields (type

, vendor

, purpose

or referrer_host

, url

, site

, country

), for example:

{ "text": "[ai-traffic-alerts] A person arrived from ChatGPT and landed on mysite.com/pricing.",
  "type": "referral", "vendor": "ChatGPT", "referrer_host": "chatgpt.com",
  "url": "https://mysite.com/pricing", "site": "mysite.com", "country": "US" }

Slack: create anIncoming Webhookand use its URL. Slack renders the top-leveltext

field, so it works with no adapter.Zapier / Make: use a "Catch Hook" trigger and branch on the structured fields.Your own API / database / CRM: consume the JSON directly.

ALERT_ON

decides which signals fire:

(the default) - only humans an AI sent you. The rare, high-value signal. Crawler detection is skipped entirely, so you need noreferrals

RADAR_KV

namespace and no throttling.- only AI crawler hits. Useful if you care about training/indexing coverage.crawlers

  • both signals.both

Empty or unrecognized values fall back to referrals

.

If you alert on crawlers, they can hit you a lot, so they are throttled to one alert per vendor per purpose per hour; human AI-referrals are never throttled, because a real person the AI sent you is the signal you always want. Change the window with CRAWLER_THROTTLE_SECONDS

(set 0

to alert on every single crawl, useful while testing). Throttling uses the optional RADAR_KV

namespace; without it the Worker still runs and simply does not dedupe. None of this applies in referrals

mode.

Simulate a human from ChatGPT: openhttps://yourdomain.com/?utm_source=chatgpt.com

in a browser. You should get an "AI sent you a visitor" alert within a few seconds. (Works inreferrals

andboth

modes.)Simulate a crawler:curl -A "GPTBot" https://yourdomain.com/

. You should get an "AI crawler" alert (once per hour per vendor unless you setCRAWLER_THROTTLE_SECONDS=0

). Only fires whenALERT_ON

iscrawlers

orboth

.

The alert names the site the visitor actually hit (the request Host). If you test against the Worker's own *.workers.dev

URL instead of a routed domain, the alert will honestly read ...workers.dev

; on your real route it shows your real domain. To pin a fixed label regardless (handy while testing), set a SITE_DOMAIN

variable in wrangler.toml

to your domain and it overrides the displayed host.

Not getting alerts? Check, in order:

Is the Worker on your traffic? In the dashboard, confirm theRoute showsyourdomain.com/*

on the right zone, and that your site is proxied by Cloudflare (orange cloud in DNS). A Worker with no matching route never runs.Read the Worker logs. EnableObservability first (Worker ->Settings -> Observability); that is what surfaces channel send failures. Then open the Worker ->** Logs**(ornpx wrangler tail

) and reload your test URL. The logs are explicit about the common failures:AI signal detected but NO notification channel is configured

  • you have not setNTFY_TOPIC

or any other channel.telegram channel failed: HTTP 401 ...

(or ntfy/whatsapp/discord/pushover/webhook) - the channel is set but the token, chat id, key, or URL is wrong. The status code tells you which.

A channel shows in Settings but the log says no channel is configured (or a token looks set but fails empty)? On the Deploy-from-GitHub path this means you added that value as a plaintext (Text) variable and the last build wiped it. This is true forevery channel value, not just ntfy. Re-add each one (NTFY_TOPIC

,TELEGRAM_BOT_TOKEN

, and the rest) withType: Secret, which survives builds, then redeploy.** Subscribed to the right ntfy topic?**The topic in the app must matchNTFY_TOPIC

exactly, and notifications must be enabled for the ntfy app on your phone.Crawler alert throttled? You only get one per vendor per purpose per hour. SetCRAWLER_THROTTLE_SECONDS=0

and test again.Alerts stopped after working at first? Check the Worker'sObservability logs.ntfy channel failed: HTTP 429 ... daily message quota reached

means you hit ntfy.sh's free daily limit (reached faster because the Worker publishes from Cloudflare's shared IPs, and immediately incrawlers

/both

mode). It resets daily. For reliable alerting use a per-account channel (Telegram, Discord, Pushover), self-host ntfy and setNTFY_SERVER

, or upgrade ntfy.sh.

Deploy returns HTTP 400 (before any build runs). You used Clone a public repository via Git URL and the Cloudflare GitHub App cannot create the copied repo in your account. Fork the repo to your account and import your fork instead (Option A above), or widen the Cloudflare GitHub App's repository access in GitHub under Settings -> Applications -> Installed GitHub Apps -> Cloudflare -> Configure.

The core idea - that "AI traffic" is really two separate signals (a provider fetching your page versus a human clicking through from an AI answer), detected two different ways - comes from our own analysis of real server logs: What nginx logs prove about AI traffic vs referral traffic. This tool applies those findings at the Cloudflare edge.

Crawlers are matched by user-agent token (GPTBot, ClaudeBot, PerplexityBot, and the rest), each tagged with its vendor and purpose. Matching is case-insensitive.Referrals are matched three ways: the referer hostname (chatgpt.com, perplexity.ai, gemini.google.com, claude.ai, and more); the native-app referer a mobile AI app sends (android-app://com.openai.chatgpt/

and the like); andutm_source

on the landing URL, because AI apps frequently strip the referer and stamputm_source=chatgpt.com

instead. The referrer list is deliberately high-confidence: general search (bing.com, duckduckgo.com, you.com) and social (x.com) are excluded so ordinary traffic never triggers a false "AI" alert.

ALERT_ON

gates which of the two are even looked for, so referrals

mode does no crawler user-agent matching at all. Both signature lists live at the top of src/worker.js. These signatures drift as vendors add and rename bots; the canonical, community-maintained crawler list is

ai-robots-txt/ai.robots.txt. Re-pull it periodically and reconcile the list rather than guessing a token.

Google/Gemini and Apple training opt-in.Google-Extended

andApplebot-Extended

are robots.txt control tokens that donot crawl under their own user-agent (Google's docs say so directly), so no edge tool can detect them by user-agent.Gemini: visitors yes, crawls no. You do see the humans Gemini sends you (they carry agemini.google.com

referer orutm_source

), but you will not see Gemini crawl your page: it answers from Google's existing index and has no live-fetch user-agent to catch.Copilot and Grok: the fetch is invisible; the referral depends on the platform. Our log research found their provider fetch shows up as a plain browser (an ordinary Chrome user-agent, no bot token), so there is no crawler signature to match and you will not see them crawl at all. Their human clickthroughs are a separate thing: this tool catches one whenever the click carries acopilot.microsoft.com

orgrok.com

referer or autm_source

, and cannot see one that arrives with neither (it looks like ordinary direct traffic). How often each case happens is set by the platform's referrer policy; our research measured their crawler side, not their referral share, so we do not claim a catch rate.Google AI Overviews / AI Mode referrals arrive as plaingoogle.com

and are indistinguishable from an ordinary Google click, so they are not flagged (flagging them would mislabel most of your Google traffic).User-agents can be spoofed. This is an alerting tool, so a rare spoofed crawler UA just means one extra notification, not a security hole.

The crawl-side findings above - Gemini answering from its index without fetching, and Copilot and Grok fetching as plain browsers - are from our own server-log research: What nginx logs prove about AI traffic vs referral traffic. On the referral side, whether a human click carries a referer at all is decided by the sending platform's referrer policy (not the browser), so a share of AI clickthroughs is simply unrecoverable at the edge. Measuring AI visibility evenly across every assistant needs cross-assistant measurement, not edge logs alone.

The Worker stores nothing about your visitors. It reads the user-agent, referer, and utm_source

of each request, sends you a notification, and forwards the request to your origin. The optional KV holds only short-lived throttle keys like radar:OpenAI:training

, never visitor data.

This tool tells you an AI touched your site. The harder questions - which prompts you show up for, which exact sources the assistants cite, who they recommend instead of you, and whether any of it converts - need measurement across the assistants, not just your edge logs. That is the problem SurfacedBy, the project behind this tool, works on.

Built by Ali Khallad at SurfacedBy.

MIT. Use it, fork it, ship it.

── more in #ai-tools 4 stories · sorted by recency
── more on @cloudflare 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-see-when-cha…] indexed:0 read:17min 2026-07-08 ·