A SERP Is Not a Ranking

2

2extract

Guest

Why a search results page doesn't tell you what a user saw before the first click.​


Your SEO report says your website is third in the search results.

Sounds like a fact, but in reality your customers might never actually see it.



Before they get to your result, they may have seen 4 ads, a map, product cards, videos, recommendations, AI answers, and so on. Is that really "third"?

When checking from another city, Google may show a map with nearby businesses in that slot or even a local marketplace that captures demand even before a user gets to organic results.



A SERP is not a ranking table. It is a product interface that a search engine builds for every new query, person, and market.


The customer journey does not start on your site​


Your landing page is not the first page your customer sees. In many categories, the search results page itself can be considered a landing page.



This is where a user sees:

  • how your brand is presented: which description or snippet a search engine chose for your brand;
  • who appears near you;
  • whether your competitors have ratings, prices, map or even a product card;
  • whether your query looks commercial or informational;
  • if the search engine answers the question itself (and removes any reason to click).



That is why asking "which position our site holds" is too narrow.

Instead, nowadays it is more effective to ask "who owns the first screen for this query and what are they asking the user to do next?".

This question extends beyond SEO. It is relevant to all product marketing, paid acquisition, branding, local growth, and content strategy.

What the ranking does not show​


For example, let's take a query like "best payroll software" or "wix website builder".

We will see very different forms of competition on the results page: ads, organic results, maps, shopping cards, reviews, AI answers.

chowa-ediotor_o0ucsj6g.png


A standard rank tracker will represent this with one number. And that number will not explain why a user chose a competitor, never saw your brand, or expected something different from your site.



Search demand is not the same thing as search page visibility. Keyword planner and similar tools may show people's interest and what they search. Search Console will show where your site already appears. Ahrefs can help with queries stuck on the second page.



However, there is one more layer between all these.



Sometimes a keyword can be a low-hanging fruit showing a good opportunity. But in the browser you will see that videos, maps, or large brands dominate the first page. Sometimes it is the opposite: a site may rank below its competitors, but its snippet is a way better answer to the request.

Where residential proxies fits in​


A search result has no single canonical version.

Checking from an office WiFi or a VPN datacenter IP will show different outcomes. Once you realize Google builds different screens for different markets, you need a way to observe those screens. That is where 2extract becomes useful.



2extract lets you inspect the results page from the market you want to understand. You can open the same query from a chosen market, record the structure of the results page, and see what your customers actually see. For example, which blocks appear, who takes up the visible part of the screen, what the brand snippet looks like, and where each result leads.



This turns SEO checks into real market observations.



Instead of:



Keyword: wix website builder
Position: 1



You will have:



Query: wix website builder
Market: Lithuania
Language: English
Observed: 2026-10-20, 11:20 UTC
Above organic results: 4 sponsored results, AI Overview
Brand organic result: 1; heading at 1695 CSS px; below first screen
First visible competitor: … (sponsored)
Brand snippet, excerpt: With this HTML website builder you can create a free custom website.



This is already something that a marketing team can discuss. And you will no longer speculate about why you dropped 2 positions. It will become clearer why your brand stopped appearing in the first visible block.

Start with 20-30 queries​


A large export does not make the research better.

Start with 20-30 queries connected to real team decisions:

  • queries to compare vendors;
  • local-intent queries;
  • queries that lead to a purchase;
  • queries where your brand already appears but receives few clicks.



Then group them by intent, not search volume.

Then, using 2extract, check each group in the markets where you sell or plan to sell.



Do not check only the URL position. Check what fills the visible results before the scroll. Who gets the first visible place? Does Google AI answer the question before anyone needs to click? Is there a marketplace standing between the user and your site?

What this means for content and ads​


The first thing that comes to mind in search analytics is to build a content plan from a list of missing keywords. The list can be useful, but it is not enough on its own.



First, you need to see what exactly a user sees for that query:

If the results are full of tech guides, your commercial landing page will not feel natural here.

If there is a map that sits at the top, then you need to work with a local presence, not another blog post.

If reviews and comparisons dominate, then you may need independent sources of trust.

If Google shows shopping cards, then you work with a catalog and feed, not text on a page.

And so on.



2extract helps to find that missing context from different countries. It shows more than demand and your position. It shows the space where a person makes their decision.

Set up your proxy​


Create an account, top up your balance, then open My Proxies and create a proxy, copy the connection details. Or you can create a proxy automatically via MCP.

You can connect your agent to 2extract using MCP, then describe the task in plain language. For example: "Prepare proxies for the UK, Lithuania, and Singapore." The agent will look up available locations, check balance, create proxy instances, and set up spending limits.

It is easier than doing it via the dashboard, especially if you already use AI agents for data collection.



Before you give an agent access, create a regular API key and manually configure read/write permissions for your MCP.

Read the results page with Playwright​


The proxy gives us a connection from the selected country. Now let's use it to open Google and see where the brand appears on the page.



We will need Chrome, Node.js, Playwright, and residential proxies from 2extract. The following code opens Google and reads the page layout. Save it as serp.cjs and run it with node serp.cjs. We've selected Lithuania as the default country. For Singapore and Australia, run this as COUNTRY=sg node serp.cjs and COUNTRY=au node serp.cjs:



Code:
const { chromium } = require('playwright');
const { randomUUID } = require('node:crypto');

(async () => {
  const query = 'wix website builder', brand = 'wix.com';
  const country = (process.env.COUNTRY || 'lt').toLowerCase();
  if (!process.env.PROXY_USERNAME || !process.env.PROXY_PASSWORD)
    throw new Error('Set PROXY_USERNAME (base username) and PROXY_PASSWORD');

  const browser = await chromium.launch({
    channel: 'chrome', headless: false, ignoreDefaultArgs: ['--enable-automation'],
    args: ['--disable-http2', '--disable-quic', '--disable-blink-features=AutomationControlled'],
    proxy: {
     server: 'http://proxy.2extract.net:5555',
     username: `${process.env.PROXY_USERNAME}-country-${country}-session-${randomUUID().replaceAll('-', '')}-time-20-const`,
      password: process.env.PROXY_PASSWORD,
    },
  });
  try {
    const page = await browser.newPage({ locale: 'en-GB', timezoneId: 'UTC',
      viewport: { width: 1365, height: 768 }, deviceScaleFactor: 1 });
    await page.goto('https://www.google.com/search?' + new URLSearchParams({ q: query, hl: 'en', gl: country }),
      { waitUntil: 'domcontentloaded', timeout: 30000 });
    const reject = page.getByRole('button', { name: 'Reject all', exact: true });
    await reject.click({ timeout: 5000 }).catch(error => {
      if (error.name !== 'TimeoutError') throw error;
    });
    // Take a snapshot after a short observation window.
    await page.waitForTimeout(10000);
    if (page.url().includes('/sorry/') || /unusual traffic/i.test(await page.locator('body').innerText()))
      throw new Error('CAPTCHA: no SERP collected');
    await page.evaluate(() => scrollTo(0, 0));

    const result = await page.evaluate(brand => {
      const shown = el => el && el.checkVisibility({ visibilityProperty: true, opacityProperty: true });
      const y = el => Math.round(el.getBoundingClientRect().top + scrollY);
      const seen = new Set();
      // Standalone web cards only; count each card once, even without a snippet.
      const organic = [...document.querySelectorAll('#rso h3')].filter(shown).map(h => {
        const card = h.closest('[data-snc],.g');
        if (!card || seen.has(card) || h.closest('[data-text-ad],[data-scope-id="turn"]')) return null;
        const cite = card.querySelector('cite')?.innerText || '';
        if (!cite || /\bviews?\b.*\bago\b/i.test(cite)) return null;
        seen.add(card);
        const host = cite.match(/((?:[a-z0-9-]+\.)+[a-z]{2,})/i)?.[1]?.toLowerCase().replace(/^www\./, '');
        return { host, h, y: y(h), snippet: card.querySelector('.VwiC3b')?.innerText || null };
      }).filter(Boolean).sort((a, b) => a.y - b.y);
      const index = organic.findIndex(r => r.host === brand || r.host?.endsWith('.' + brand));
      if (index < 0) throw new Error('Brand not found among supported web cards');
      const target = organic[index], first = organic[0], rect = target.h.getBoundingClientRect();
      const ads = [...document.querySelectorAll('[data-text-ad]')]
        .filter(c => !c.querySelector('[data-text-ad]'))
        .map(c => [...c.querySelectorAll('h3,[role="heading"]')].find(shown))
        .filter(h => h && y(h) < first.y);
      const ai = [...document.querySelectorAll('h1,h2,[role="heading"]')]
        .some(h => shown(h) && h.innerText.trim() === 'AI Overview' && y(h) < first.y);
      return { organicRank: index + 1, headingY: target.y,
        inFirstScreen: rect.bottom > 0 && rect.top < innerHeight && rect.right > 0 && rect.left < innerWidth,
        adsBeforeOrganic: ads.length, aiBeforeOrganic: ai, snippet: target.snippet,
        googleLocation: document.querySelector('#footcnt')?.innerText.trim() || null };
    }, brand);
    console.log(JSON.stringify({ query, country, language: 'English',
      observed: new Date().toISOString(), ...result }, null, 2));
  } finally { await browser.close(); }
})().catch(error => { console.error(error.message); process.exitCode = 1; });



Where did the organic link appear?​


We ran a simple test with the query "wix website builder" from different countries using 2extract proxies. We kept the interface language set to English and the browser viewport at 1365 × 768. We changed the "gl" parameter to match the search country context.

Google accurately identified the country on each results page and displayed it at the bottom, saying that the location is derived from the IP address.



Here are the results:




Market

Organic position

Title position (px from the top)

What was above the search result

Lithuania

1

1695px

Four Ads and AI overview

Singapore

2

1074px

AI overview, link to the App Store, and "People also ask"

Australia

2

1927px

Two ads, AI overview, link to the expert market review and "People also ask"

In Lithuania, the target website ranked first in organic results, but its result appeared 621 pixels farther down the page than in Singapore, where it ranked second! It ranked second in both Singapore and Australia, but in Australia the result appeared 853px farther down. That's more than a full viewport. In all 3 cases, the result title was below the fold. Position number alone doesn't capture this difference.



In Lithuania, the first screen was filled with ads:



chowa-ediotor_anebmur.png


In Singapore, the first screen showed an AI overview and an App Store listing. The link to the target website was way below:

chowa-ediotor_p6ms4rp.png


On the second check in Lithuania, the website still ranked first, but the number of ads changed from 2 to 4. Its result title had moved from 1489 to 1695 pixels down the page. In both Singapore checks, the website ranked second, with its result title starting at around 1075 pixels.

So, the result can change even with unchanged organic rank.



Moreover, the target brand appeared in AI Overviews, and in Australia it also had an ad above its organic link. The brand was present in several places on the page.

What does all this tell us?​


We tried loading search results 30 times across 3 different queries and various proxies. Sometimes we got CAPTCHAs; sometimes we hit errors.



We changed queries and reused successful sessions, so this was not a test of proxy success rates.

To collect results at scale, you'd need to control rate limits, track failed loads, and keep the parser up to date.

For an initial market check, compare organic rank results with their pixel position, the blocks above them, and other brand appearances. In our test, a #1 result appeared farther down the page than a #2 result, while two #2 results differed by more than one screen in height.



SEO tools measure rankings. Customers experience interfaces. If you optimize only the metric, you may never improve the experience.



Or, in other words, if you work only with search results exported from an SEO tool, then you see a map, not the territory.

Start with one product question, a few queries, and one target market. Open search results from your customer's market via 2extract proxies and study what people actually see. Then it becomes far clearer what exactly you need to change: text, ads, local presence, snippets, or even the product itself.
 

Thread statistics

Created
2extract,
Replies
0
Views
0
Back
Top