The #1 mistake with google.com/goto right now
People see google.com/goto?url=CAES... and immediately try to base64-decode the blob or fire a HEAD request. Both fail. The token is an opaque protobuf reference, not an encoded URL, and HEAD often comes back 200 with no Location header at all.
Late 2026 SEO Discords and AI-agent threads lit up when rank trackers briefly broke. Panic was louder than the fix. Either pair the token with the real URL already sitting in the SERP data blob, or send one GET that stops at the redirect and read Location. Concrete steps below.
What actually changed under the hood
For years the organic title href held the destination (or a readable /url?q= wrapper). Now – especially on signed-out or private sessions – many results point at https://www.google.com/goto?url=CAES.... Humans still click through fine. Scrapers that only stored the href woke up full of Google links.
According to a Google spokesperson via Search Engine Roundtable, the company is deploying “technical measures against evolving forms of abuse.” Real cost: one extra hop (or smarter parsing) before you know the destination. Copies of that destination stay on the page for favicons, sitelinks, and rendering – Google still has to draw the SERP.
Pro tip: Treat CAES as a one-time ticket, not an ID. It changes on every page load and repeats across title/thumbnail/favicon anchors for the same card. Deduplicate tokens first.
Logged-in Chrome sometimes still shows direct links. Brave and LibreWolf often keep them. Safari may wrap CAES inside the older /url path. No single trigger is documented – build for multiple formats.
Step-by-step: resolve a goto link the reliable way
Two paths. Prefer the zero-request one when you already have the HTML.
1. Pair from the page data (fastest)
Most organic cards already expose the clean URL next to the token. Inspect the large JSON-ish blob Google embeds for its own JS – token, title, snippet, and destination sit in consecutive tuples. Match them and you are done. Zero extra traffic to Google. Testers at OpenWeb Ninja recovered the majority of results this way on captured pages.
2. Resolve via Location header
When the blob misses a link (some videos, Lens, edge cards) or you only hold the href:
import requests
goto = "https://www.google.com/goto?url=CAES..." # full token from href
r = requests.get(
goto,
allow_redirects=False,
headers={"Referer": "https://www.google.com/search"},
timeout=10,
stream=True,
)
print(r.status_code) # usually 302
print(r.headers.get("Location")) # real destination
r.close()
Use GET, not HEAD. ScrapingBee tests and curl probes show HEAD frequently returns 200 with an empty Location. Do not follow the redirect to the target site – you only need the header. Some responses land on non-3xx statuses yet still carry Location; always check the header. Modest delay and connection reuse help when you batch.
curl version:
curl -s -D - -o /dev/null --max-redirs 0
-H 'Referer: https://www.google.com/search'
'https://www.google.com/goto?url=CAES...' | grep -i '^location:'
Common pitfalls that still bite people
- Assuming every SERP is goto – mix of direct, /goto, and /url+CAES exists. Detect and branch.
- Caching on the token – worthless; tokens rotate. Cache the resolved destination.
- Forgetting duplicates – one result can emit the same CAES three times. Unique the set before resolving.
- Bulk without throttle – five pages of rankings can mean 500-1,000 resolution calls (Nozzle / Derek Perkins figures reported via PPC Land). Rate limits hit before bandwidth does.
- Trusting hover for security checks – the status bar now shows Google’s opaque URL. Malwarebytes notes independent pre-click preview is weaker even though the green domain text still appears.
Remember that one-time-ticket idea? Same token still resolved across IPs in community checks, and multi-day-old tokens kept working. Upper bound on lifetime is undocumented – Google has not published permanence, exact /goto rate limits, or max age. Bulk resolvers feel practical throttling fast.
Old wrappers vs paid APIs (as of late 2026)
| Approach | Extra requests | Works offline? | Notes (as of late 2026) |
|---|---|---|---|
| Old /url?q= readable | 0 | Yes | Mostly gone for organic on affected sessions |
| Page JSON pairing | 0 | Yes (with HTML) | Best first pass; covers majority of cards |
| GET + Location | 1 per unique token | No | Reliable fallback; watch status + header |
| SerpApi / Autom / similar | 0 for you | N/A | They resolve server-side; your integration stays clean |
Occasional checks? Pairing or a tiny userscript is enough. Daily rank jobs or RAG pipelines? Paid SERP APIs absorbed the change within days – SerpApi, Autom, Semrush, Ahrefs and others return clean destination fields again – so your code never sees CAES.
One open question the docs still leave hanging: will Google bind tokens tighter to session or IP, or throttle the /goto endpoint harder? Community reports already treat bulk resolution as the expensive path.
FAQ
Does this break my website or Search Console?
No. Rankings signals and GSC reports are unchanged. Only third-party href parsers needed updates.
Can I just decode the CAES string myself?
Base64url-decode it and you get a tiny protobuf envelope (field 1 = 1, field 2 = protected bytes). No public URL inside. Testers found no local transform that recovers the destination – offline reverse is a dead end. Pair or resolve instead.
I’m building a small AI agent that scrapes a few SERPs. What should I ship first?
Detect three shapes: plain external URL, /goto?url=CAES, and /url?...&url=CAES. Prefer the embedded data blob when it is present. Fall back to one non-following GET per unique token, Referer set, short sleep between calls. Log any non-302 that still carries Location. That covers the current rollout without turning every query into a hundred extra round-trips. Volume grows? Hand the heavy lifting to a maintained SERP API.
Open a private window, search something, grab one goto href, and run the GET snippet above. Once you see the clean Location, wire the same logic into your parser tonight.