{"slug": "google-removed-the-urls-only-for-the-people-who-resell-them", "title": "Google removed the URLs. Only for the people who resell them", "summary": "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.", "body_md": "On August 26, 2026, [PPC Land reported](https://ppc.land/google-forces-rank-trackers-into-500-to-1-000-requests-per-query/) 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=`\n\nwith an encoded string. When you click, Google redirects you to the real page on their server side.\n\nIn 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.\n\nGive your AI a web data layer –\n\nturns any site into clean, structured data your models can actually use.[Decodo’s Web Scraping API]\n\nMost 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.\n\nBoth were right in their own way since this isn’t a standard rollout. It’s Google responding to something.\n\nIf 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.\n\n## Two windows, one variable\n\nHere’s an experiment you can try yourself. It only takes about four minutes.\n\nStart 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.\n\n``` js\n(()=>{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);})()\n```\n\nThen, open a second Chrome window, again with a fresh profile and the same connection, but this time add the `--remote-debugging-port`\n\nflag. Don’t attach anything to that port and don’t automate anything. Just type the same query by hand.\n\n```\nwindow                                  goto  direct  total\nfresh profile, no debug port               0     213    215\nfresh profile, --remote-debugging-port    96       0    106\nfresh profile, --remote-debugging-port    83       0     93\n```\n\nHTTP/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.\n\nEverything 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.\n\nBoth 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.\n\nI 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.\n\nSo, 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.\n\n## What this actually means\n\nIf 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.\n\nThis 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.\n\nFor me, this is more interesting than just a link format change. Blocking is obvious: you’re either in or out, and you know it.\n\nHere, 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.\n\nThere’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.\n\n## What the wrapped page contains\n\nTen 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:\n\n```\nin-result anchors : 408\ngoto wrappers     : 339\ndirect URLs       :   0\nold /url? wrappers:   0\n```\n\nIn every capture, I found zero direct destinations. The old `/url?q=`\n\nwrapper, 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`\n\nattribute.\n\nThe 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.\n\n## The token is protobuf, and that doesn’t help you\n\nOne question I had was: can the token be reverted to the URL? Of course, not.\n\nEvery token starts with `CAES`\n\n. 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.\n\n```\nfield 1, wire 0, value 1\nfield 2, wire 2, len 99..119\n```\n\nThe 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.\n\nWhat 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.\n\n## HEAD is not refused, which is worse\n\nAnother 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.\n\nWhat we measured from our test is annoying instead. Across 50 wrapped links resolved from the home line with `curl_cffi`\n\nand redirects disabled:\n\n``` php\nHEAD  ->  200 on all 50, Location header present on 0\nGET   ->  302 on all 50, Location header present on 50\nmedian GET latency  : 59 ms\nmean bytes per GET  : 1068 B (headers plus body, redirect not followed)\n```\n\nHEAD 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.\n\nGET 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.\n\n## The mapping is not stable, so there is no lookup table\n\nThe 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 reloading. Forty-six results appeared in more than one capture.\n\n```\nresults seen in more than one capture : 46\ntoken identical                       : 0\ntoken changed                         : 46\n```\n\nNone of the tokens are stable. The same link to the same page on the same query gets a new token every time. The `CAES`\n\nand `01 EB 3B 30 15`\n\nprefix stays the same, but the rest changes completely. In one case, I saw a result with 24 different tokens across my tests.\n\nThis 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.\n\nThose 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.\n\n### Where the destination leaks anyway\n\nIn three out of ten captures, I actually got some destinations in the clear, and I doubt that’s intentional.\n\nWhen 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=`\n\nwith the target sitting in the clear:\n\n```\nhttps://www.salesforce.com/eu/crm/pricing/\nhttps://www.zoho.com/en-us/crm/zohocrm-pricing.html\nhttps://www.creatio.com/glossary/crm-pricing\n```\n\nI 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.\n\nThis 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.\n\n### What’s the cost of this modification?\n\nOn 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.\n\nThe good news is that solving these tokens actually takes almost nothing. I tried resolving the same links four different ways: using `curl_cffi`\n\nwith full Chrome TLS impersonation, and with plain requests, both with and without a Referer header. No cookies, no session, no proxy involved.\n\n```\nrequests, no referer      12/12 resolved, 302 + Location, median 124 ms, 1269 B\nrequests, with referer    12/12 resolved, 302 + Location, median 137 ms, 1268 B\ncurl_cffi, no referer     12/12 resolved, 302 + Location, median 115 ms, 1479 B\ncurl_cffi, with referer   12/12 resolved, 302 + Location, median 123 ms, 1479 B\n```\n\nPlain 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.\n\nTokens 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.\n\nNow, 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:\n\n```\nconcurrency  1:  60/60 resolved,  7.8 req/s\nconcurrency  5:  60/60 resolved, 35.1 req/s\nconcurrency 10:  60/60 resolved, 56.9 req/s\nconcurrency 20: 200/200 per chunk, six chunks, 110 req/s sustained\n```\n\nA tenth of a second, maybe two. In a multi-second answer, that’s real but manageable.\n\nSo, if the costs for solving these tokens are minimal, why did Google bother to put this feature in place?\n\nThe 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.\n\nThat gives Google three things it didn’t have before.\n\nFirst, a throttle it controls, where the visible symptom is someone else’s product getting slow.\n\nSecond, a live view of how many results each consumer dereferences and when, which is a decent proxy for their query volume.\n\nThird, 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.\n\nThis means more Google control over a certain type of third-party services, but not its direct competitors in the LLM space.\n\nClaude’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](https://simonwillison.net/2025/Mar/21/anthropic-use-brave/) and is [still there in July 2026](https://xponent21.com/insights/claude-web-search-brave-turbopuffer/), the search function carries a `BraveSearchParams`\n\nparameter, and the citations match what Brave returns for the same query. ChatGPT is more mixed. It [launched on Bing](https://searchengineland.com/chatgpt-retrieval-stack-index-cache-pages-485036), then built its own crawler and index, and now runs a blended stack with Bing still contributing alongside third-party providers.\n\nNeither of them reads a Google results page, so they’re not touched by this deploy.\n\nThat 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.\n\nThe most prominent vendor in the reachable group is the one Google currently has in court.\n\n[As a Google spokesperson said to Seroundtable.com](https://www.seroundtable.com/google-search-goto-tracking-41957.html): “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.\n\nNone 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.\n\nThe 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.", "url": "https://wpnews.pro/news/google-removed-the-urls-only-for-the-people-who-resell-them", "canonical_source": "https://www.scraping.club/p/google-removed-the-urls-serp", "published_at": "2026-08-30 14:04:38+00:00", "updated_at": "2026-08-30 14:21:51.425154+00:00", "lang": "en", "topics": ["ai-tools", "ai-infrastructure"], "entities": ["Google", "PPC Land", "Nozzle", "Derek Perkins", "Chrome"], "alternates": {"html": "https://wpnews.pro/news/google-removed-the-urls-only-for-the-people-who-resell-them", "markdown": "https://wpnews.pro/news/google-removed-the-urls-only-for-the-people-who-resell-them.md", "text": "https://wpnews.pro/news/google-removed-the-urls-only-for-the-people-who-resell-them.txt", "jsonld": "https://wpnews.pro/news/google-removed-the-urls-only-for-the-people-who-resell-them.jsonld"}}