cd /news/ai-tools/google-removed-the-urls-only-for-the… · home topics ai-tools article
[ARTICLE · art-115774] src=scraping.club ↗ pub= topic=ai-tools verified=true sentiment=· neutral

Google removed the URLs. Only for the people who resell them

Google has begun replacing destination URLs in search results with redirect links for automated queries, requiring 500 to 1,000 requests to resolve a five-page ranking, according to a report by PPC Land and measurements by Derek Perkins at Nozzle. The change appears targeted at bots: in a test by the author, a fresh Chrome profile with the --remote-debugging-port flag received 96 wrapped links and zero direct URLs, while a normal profile received 213 direct URLs, indicating Google serves different results to automated clients.

read13 min views5 publishedAug 30, 2026
Google removed the URLs. Only for the people who resell them
Image: source

On August 26, 2026, PPC Land reported a Google change that most people probably missed unless they work with rank tracking. Now, when you look at search results, the links no longer show the real site address. Instead, they all point to google.com/goto?url=

with an encoded string. When you click, Google redirects you to the real page on their server side.

In the same article, Derek Perkins at Nozzle measured what this means in practice. If you want to resolve all the links for a five-page ranking, you need between 500 and 1,000 requests. You can’t decode these links yourself, and HEAD requests won’t give you the answer. The only way to know where each result points is to ask Google for every single link.

Give your AI a web data layer –

turns any site into clean, structured data your models can actually use.[Decodo’s Web Scraping API]

Most people talked about this as if it were a typical rollout, something Google would turn on for everyone over time. That’s why Barry Schwartz checked for it on his own machine and didn’t see anything, while Nozzle saw it almost everywhere.

Both were right in their own way since this isn’t a standard rollout. It’s Google responding to something.

If you see it this way, the cost story isn’t as dramatic as it sounds. I’ll show you the numbers, but to sum up: those 500 to 1,000 requests are real, they’re cheap, and honestly, they’re not the real problem.

Two windows, one variable #

Here’s an experiment you can try yourself. It only takes about four minutes.

Start by opening Chrome with a fresh profile and search for something commercial (I used “best running shoes”). In the console, count how many result links go directly to the destination and how many use the goto wrapper, using this script.

(()=>{const f=()=>{const a=[...document.querySelectorAll('#rso a[href], #search a[href]')];const h=x=>x.getAttribute('href')||'';return `goto=${a.filter(x=>h(x).includes('/goto?')).length} direct=${a.filter(x=>/^https?:\/\//.test(h(x))&&!/google\.|gstatic/.test(h(x))).length} total=${a.length}`};console.log('t0',f());setTimeout(()=>console.log('t+5s',f()),5000);setTimeout(()=>console.log('t+20s',f()),20000);})()

Then, open a second Chrome window, again with a fresh profile and the same connection, but this time add the --remote-debugging-port

flag. Don’t attach anything to that port and don’t automate anything. Just type the same query by hand.

window                                  goto  direct  total
fresh profile, no debug port               0     213    215
fresh profile, --remote-debugging-port    96       0    106
fresh profile, --remote-debugging-port    83       0     93

HTTP/3 and QUIC run on UDP, so the proxy layer has to carry it too.[anyIP]gives compatible clients production-ready SOCKS5 UDP ASSOCIATE across its residential and mobile network for your SERP scraping.

Everything else stays the same: same machine, same home connection, same query, just a few minutes apart. Without the flag, you see 213 destination URLs in the HTML, just like before. With the flag, you get zero direct URLs and 96 wrapped links instead.

Both results are stable. I checked each page at load, after five seconds, and after twenty seconds, and the counts never changed. So it’s not JavaScript changing the page later. The difference comes from what Google sends you right from the start.

I ran nine more tests using a stealth browser with full automation, and every time I got zero direct URLs, always wrapped. But when I browse normally, logged in or in a private window, I never see any wrappers at all.

So, from my little experiment, it seems that Google detects when I’m using an automated solution and serves me different results. The key factor for showing URLs or not is whether Google thinks it’s talking to a human or a script.

What this actually means #

If you look at the reports with this in mind, it all makes sense. Schwartz didn’t see the behavior because he was just using his browser. Nozzle saw it everywhere because they’re a rank tracker, and Google had already classified their traffic. What people called a ‘bucketed rollout’ was really just two different groups seeing two different things.

This also changes what those 500 to 1,000 requests really mean. That’s not the new baseline cost for scraping Google. It’s what you pay after Google has recognized you. If you haven’t been flagged, the addresses are still in the markup, ready to grab for free.

For me, this is more interesting than just a link format change. Blocking is obvious: you’re either in or out, and you know it.

Here, Google still gives you results, the page loads, your parser can still find titles, positions, and snippets. Everything works. The only thing missing is that one field, and now you have to pay a network round trip for each row to get it.

There’s no warning when this happens. A pipeline that worked fine in June still returns HTTP 200 and well-formed HTML today, but the data quality quietly drops in the meantime.

What the wrapped page contains #

Ten captures on the treatment side, across two queries, nine from a stealth browser and one read over CDP from a page a person opened by hand:

in-result anchors : 408
goto wrappers     : 339
direct URLs       :   0
old /url? wrappers:   0

In every capture, I found zero direct destinations. The old /url?q=

wrapper, which at least left the address in plain text, is gone too. Now, every organic link, every video timestamp, and every ‘translate this page’ link is wrapped. They all have a ping

attribute.

The difference between the number of anchors and wrappers comes from Google’s own navigation. For example, on the CRM software pricing page, 18 out of 38 in-result anchors are related searches, and three are ad links. All 17 external destinations are wrapped.

The token is protobuf, and that doesn’t help you #

One question I had was: can the token be reverted to the URL? Of course, not.

Every token starts with CAES

. Base64 decoded, that’s 08 01 12: protobuf field 1 as a varint set to 1, then field 2 as a length-delimited blob. A field walk over the decoded bytes confirms it.

field 1, wire 0, value 1
field 2, wire 2, len 99..119

The blob inside field 2 is where the destination should be, and it isn’t there. Every one of the 183 distinct tokens we collected opens with the same five bytes, 01 EB 3B 30 15, and everything after is high entropy noise. We measured 6.27 to 6.44 bits per byte over roughly a hundred bytes, which is what you get on random or encrypted data. Base64, base64url, percent decoding first, gzip and zlib on the result, none of them produce a single printable URL fragment.

What you see here is a constant header followed by an opaque payload, just like you’d expect from a key identifier and ciphertext. You can’t decode this yourself because you don’t have the key. Reversing an encoding is one thing, but getting a key from Google is a whole different story. So, the only way to get the destination is to let Google look it up for you, one request at a time.

HEAD is not refused, which is worse #

Another idea could be to use HEAD requests, so that in cases of redirects, the Location header contains the final URL. This could be a faster way to check which URL the token corresponds to.

What we measured from our test is annoying instead. Across 50 wrapped links resolved from the home line with curl_cffi

and redirects disabled:

HEAD  ->  200 on all 50, Location header present on 0
GET   ->  302 on all 50, Location header present on 50
median GET latency  : 59 ms
mean bytes per GET  : 1068 B (headers plus body, redirect not followed)

HEAD requests aren’t blocked. You get a 200 response, but no redirect. If you just log the requests, you’ll see fifty successes but get nothing useful, and you’ll have to figure out why. The usual HTTP cache path doesn’t fail with an error. It just looks like it worked, which can waste a lot of time before you realize what’s going on.

GET requests work as expected: one per link, you get a 302 with a Location header, and you have the destination. I tried fifty of these from a home IP and didn’t hit any rate limits, so the throttle is set higher than that.

The mapping is not stable, so there is no lookup table #

The last mitigation idea I had was to create a lookup table between tokens and final URLs. We compared the token attached to each result title across all captures. That covers three reloads inside one accepted session and several entirely separate browser sessions, hours apart, which is a harder test than re. Forty-six results appeared in more than one capture.

results seen in more than one capture : 46
token identical                       : 0
token changed                         : 46

None of the tokens are stable. The same link to the same page on the same query gets a new token every time. The CAES

and 01 EB 3B 30 15

prefix stays the same, but the rest changes completely. In one case, I saw a result with 24 different tokens across my tests.

This answers a question that came up in the original discussion. You can’t build a lookup table and reuse it, because there’s nothing stable to key it on. The payload is tied to the impression, not the destination, so you pay the full resolution cost every time. I tried to find a caching trick here, but there isn’t one.

Those reloads showed me something else. They were automated navigations using a script over CDP, but the session was started by a human. Google allowed all of them. Once Google accepts a session, it keeps working even if you automate it. The real check happens when you submit the query, not after.

Where the destination leaks anyway

In three out of ten captures, I actually got some destinations in the clear, and I doubt that’s intentional.

When Google offers to translate a result, the “translate this page” link is usually a wrapper, but sometimes it’s a plain translate.google.com/translate?u=

with the target sitting in the clear:

https://www.salesforce.com/eu/crm/pricing/
https://www.zoho.com/en-us/crm/zohocrm-pricing.html
https://www.creatio.com/glossary/crm-pricing

I checked if those were the same destinations you’d otherwise have to resolve. Looking at the first eight wrapped links and resolving them, six were already available for free in a translate link. The other two were Italian results, which Google didn’t offer to translate.

This happened in three out of ten captures, using the same queries and the same browser. I couldn’t figure out what triggers it. I think of it as a discount that sometimes shows up, so always check for it before you spend a request.

What’s the cost of this modification?

On a wrapped page, I saw between 59 and 113 wrapper anchors, depending on how many results there were. After deduplication, that’s 59 unique tokens on my reference page. For a five-page ranking, that’s 565 requests if you resolve every anchor, or 295 after deduplication. The 500-1,000 range makes sense if you just resolve everything, which is probably what most people do.

The good news is that solving these tokens actually takes almost nothing. I tried resolving the same links four different ways: using curl_cffi

with full Chrome TLS impersonation, and with plain requests, both with and without a Referer header. No cookies, no session, no proxy involved.

requests, no referer      12/12 resolved, 302 + Location, median 124 ms, 1269 B
requests, with referer    12/12 resolved, 302 + Location, median 137 ms, 1268 B
curl_cffi, no referer     12/12 resolved, 302 + Location, median 115 ms, 1479 B
curl_cffi, with referer   12/12 resolved, 302 + Location, median 123 ms, 1479 B

Plain requests work just fine. The stealth setup you needed to get the page isn’t needed to resolve the links. You don’t need a residential proxy, cookies, or even a referer, at least at this small scale.

Tokens also stay valid. I captured links one day and resolved all 12 of them the next morning, so you don’t have to resolve them right away. You can collect now and resolve later, even in bulk.

Now, about throughput. This is where people expected to hit a wall. I ran 1,200 resolutions from a regular IP using a plain client, increasing concurrency as I went:

concurrency  1:  60/60 resolved,  7.8 req/s
concurrency  5:  60/60 resolved, 35.1 req/s
concurrency 10:  60/60 resolved, 56.9 req/s
concurrency 20: 200/200 per chunk, six chunks, 110 req/s sustained

A tenth of a second, maybe two. In a multi-second answer, that’s real but manageable.

So, if the costs for solving these tokens are minimal, why did Google bother to put this feature in place?

The answer is that Google is now a synchronous dependency inside a competitor’s live product. Every user question that reaches Google’s index now needs a set of real-time callbacks to google.com before the answering system can read a single page.

That gives Google three things it didn’t have before.

First, a throttle it controls, where the visible symptom is someone else’s product getting slow.

Second, a live view of how many results each consumer dereferences and when, which is a decent proxy for their query volume.

Third, the machinery to apply both selectively, since the classifier that decides who gets wrapped markup is the same one that could decide who gets rate-limited.

This means more Google control over a certain type of third-party services, but not its direct competitors in the LLM space.

Claude’s web search appears to run on Brave Search. Anthropic has never said so publicly, but Brave Search has been on its published subprocessor list since March 2025 and is still there in July 2026, the search function carries a BraveSearchParams

parameter, and the citations match what Brave returns for the same query. ChatGPT is more mixed. It launched on Bing, then built its own crawler and index, and now runs a blended stack with Bing still contributing alongside third-party providers.

Neither of them reads a Google results page, so they’re not touched by this deploy.

That narrows the target a lot. The companies with real exposure are the ones whose whole product is Google’s index resold with low latency, the SERP API vendors that sit between Google and everyone building on top of search. They can’t route around this like an assistant with its own index, because Google’s index is what they sell. Their customers want results in a second or two, which puts the resolution stage inside a latency budget set by someone else.

The most prominent vendor in the reachable group is the one Google currently has in court.

As a Google spokesperson said to Seroundtable.com: “We have a long history of deploying technical measures against evolving forms of abuse, and we regularly take steps to protect our services and users.” No target, no timetable, no documentation, and no acknowledgment that two clients asking the same question get different pages.

None of this is a rule anyone has to enforce, and that’s what makes it durable. A block can be litigated, and Google already lost once, on the grounds that reading a page counts as circumvention. Serving valid HTML with one field removed to clients you have classified isn’t a refusal of service, and there’s nothing to appeal against.

The cost for this particular field is actually small, and that’s important to keep in mind. What matters isn’t the 295 requests. It’s that Google can now separate the two groups well enough to send them different markup, quietly, with no announcement and no error in your logs. The field it removed this time is cheap to buy back with a GET. Nothing about the mechanism says the next one will be.

── more in #ai-tools 4 stories · sorted by recency
── more on @google 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/google-removed-the-u…] indexed:0 read:13min 2026-08-30 ·