Deep dive· Search strategy · 13 min read

Where to start with Search campaigns on a huge site? Your GA4 already knows.

On a huge site, the first Search question isn't keywords — it's which landing pages can afford to be advertised. GA4 economics answers it, step by step.

Giant landing-page doors sorted onto YES and NO piles.
The serious facts are real — the article covers are not.

In short: On a huge site the first Search question isn't keywords — it's which landing pages can mathematically afford to be advertised. Feed in a GA4 export plus a site crawl, compute maxCPC = target CRR × CR × AOV per page, and compare it to your real average CPC. Out comes a ranked TOP 100–200 build pile, a fix pile of trouble pages, and a skip pile — before you spend a cent.

TOP 100–200
landing pages worth building first
CRR × CR × AOV
the max CPC each page can afford
~3 min
to set up the crawl extraction
€0.10 CPC
the pages you should never bid on

What you put in, and what you get out

You put in two things you already own: a GA4 export of your landing pages and a crawl of your site. You get back one thing — a ranked list of the landing pages worth a Search campaign first, each with the exact max CPC it can afford, and a clean “don’t bid on this” pile for the pages whose economics forbid paid search. No keyword tool, no hunch, no “let’s just turn on Dynamic Search Ads and see.” A spreadsheet that tells you where to point the budget before you spend a cent of it.

That’s the whole article. Below I run the pipeline end to end and, at every step, show you the literal thing it spits out — the GA4 rows, the max-CPC arithmetic on a single line, the crawl extraction table, the prioritization sort before and after, and the trouble-page diagnosis that rescues a page everyone else would delete. The numbers are illustrative throughout — plug in your own — but the shapes are exactly what the tools return.

Why bother with a pre-flight at all? Because the default move on a 10,000-URL site is to point a broad campaign at everything and let Google sort it out. That torches budget on pages that were never going to convert, drags your target ROAS loose, and poisons the learning phase. This filter is the cheapest insurance you’ll ever buy.

The pipeline in one box

  • What we're after The landing pages worth advertising, ranked
  • Inputs GA4 landing-page export · a site crawl
  • The one formula maxCPC = target CRR × CR × AOV
  • What you get A build pile, a fix pile, and a skip pile

The one number that decides everything: max CPC

Every landing page has a ceiling — the most you can pay for a click and still hit your target efficiency. Compute it per page and the whole prioritization falls out of the math:

maxCPC = target CRR × CR × AOV

where CRR (cost-revenue ratio — the European PNO, equivalent to ACOS) is the share of revenue you’re willing to spend on ads, CR is the page’s conversion rate, and AOV is its average order value.

A worked example, straight from the formula. A category page converts at 2%, averages a €1,000 order, and you’re willing to spend 10% of revenue on ads (a 10× ROAS):

maxCPC = 0.10 × 0.02 × €1,000 = €2.00.

If you prefer to think in ROAS, the same thing rearranges to maxCPC = CR × AOV / ROAS = 0.02 × 1,000 / 10 = €2.00. Same number, pick the form your brain likes. (Illustrative example.)

That €2.00 is the verdict. Compare it to the real average CPC in your account for that market and the page sorts itself: comfortably above avg CPC → build it; below → it can’t pay its way; far below → don’t even think about it. Everything that follows is just producing this number for every page, reliably, and reading the result.

The pipeline at a glance

Five steps. For each one: what you do, what you’re looking at, and why — because every step exists to answer one specific question about a page.

1 — Pull landing-page economics from GA4

Do: per landing page, export sessions, conversions, transactions and revenue; derive CR and AOV. Why: this is the demand-and-money signal — without it max CPC is a guess. You get: one row per page carrying the two numbers the formula eats (CR and AOV).

2 — Crawl the site for structure

Do: crawl every page for title, H1, breadcrumb depth and — the one that matters — how many products it lists. Why: GA4 knows economics but not structure; a page with two products in stock can’t carry a campaign no matter how it converts. You get: the structural mirror of your GA4 rows, plus a thin-page flag.

3 — Join the two, compute max CPC

Do: join GA4 + crawl by URL, run the formula on every row, drop thin pages. Why: this is where economics and structure meet and the verdict becomes computable. You get: every page with a max CPC sitting next to it.

4 — Prioritize: max CPC vs. real avg CPC

Do: put each page’s max CPC next to the actual average CPC in your account or country, sort by headroom. Why: a max CPC means nothing in isolation — only the gap to what clicks actually cost decides if a page can pay. You get: the TOP 100–200 build pile, a fix pile, and a skip pile.

5 — Diagnose the trouble pages

Do: for pages that should convert but don’t, check the price-competitiveness of the products they list first. Why: a low CR on a page that ought to sell is usually a merchandising leak, not a demand problem — and it’s fixable. You get: pages rescued from the skip pile back into the build pile, once they can actually convert.

Now the same five steps, one at a time, each with the literal thing it produces.

Step 1 — The GA4 export, as it lands

You don’t need a fancy report. In GA4: Explore → blank → Free form, dimension Landing page + query string, metrics Sessions, Key events / Conversions, Total revenue. Add Transactions if you have it; otherwise AOV comes from revenue ÷ conversions. One filter up front: exclude product detail pages and keep category / collection pages — you’re sizing where to send traffic, and on most sites that’s categories, not individual SKUs. Mixing SKUs in skews every AOV and CR you compute.

Here is what four representative rows look like once exported, with CR and AOV derived:

Landing page         Sessions  Conv   CR     Revenue    AOV
/cordless-vacuums       8,140    163   2.0%   €68,460    €420
/winter-tyres           5,020    156   3.1%   €28,080    €180
/sleeping-bags         12,300    135   1.1%   €12,825    €95
/phone-cases            9,800    137   1.4%    €2,192    €16

(Illustrative example.) CR is conversions ÷ sessions; AOV is revenue ÷ conversions. That’s the entire input the formula needs from GA4 — two columns, CR and AOV, per page. Notice already that /sleeping-bags pulls the most sessions in the set yet converts the worst; hold that thought, it’s the interesting one later.

Step 2 — The crawl, and the column that does the work

GA4 told you how each page performs. It can’t tell you a page is structurally hollow — a “category” with two products in stock, or a parametric filter view that should never carry a campaign. For that you crawl. Two routes: have an AI write you a throwaway crawler in five minutes, or use Screaming Frog with a custom XPath extraction you set up in about three minutes (full mini-guide in the steal box). Run it in List mode on your GA4 URL set and it grinds in the background while you do something else.

The one column that earns its keep is the product count — how many product cards the page actually renders. Here’s the extraction output joined to the same four pages, plus one more the crawl flags:

URL                  Title                H1               Products  Breadcrumb
/cordless-vacuums    Cordless Vacuums …   Cordless Vacuums      48    Home>Floorcare>Vacuums
/winter-tyres        Winter Tyres | …     Winter Tyres        112    Home>Tyres>Winter
/sleeping-bags       Sleeping Bags …      Sleeping Bags         9    Home>Camping>Sleep
/phone-cases         Phone Cases …        Phone Cases         640    Home>Accessories>Cases
/clearance-2019      Clearance            Clearance             0    Home>Clearance

(Illustrative example.) The thin-page rule does its job on the spot: /clearance-2019 lists 0 products — an empty category that GA4 still logs sessions against. Drop any page under ~3 products before you prioritize, and that ghost page never reaches the build pile. Mini-example, situation → action → result: the crawl shows a “category” with zero live products → you exclude it pre-prioritization → you don’t waste a campaign (or an analyst’s afternoon) on a page with nothing to sell.

Step 3 — Join the two, and the formula on a single row

Now the two datasets become one. Join GA4 + crawl by URL and every page carries both its economics (CR, AOV) and its structure (product count). Run maxCPC = target CRR × CR × AOV down the column. Watch it land on one real row — /cordless-vacuums, target CRR 10%:

maxCPC = 0.10 × 0.020 × €420 = €0.84.

One line, one ceiling. Do it for all four survivors and you get the per-page max CPC the whole decision hangs on:

Page                CR     AOV    CRR    maxCPC = CRR×CR×AOV
/cordless-vacuums   2.0%   €420   10%    0.10 × 0.020 × 420 = €0.84
/winter-tyres       3.1%   €180   12%    0.12 × 0.031 × 180 = €0.67
/sleeping-bags      1.1%    €95   10%    0.10 × 0.011 ×  95 = €0.10
/phone-cases        1.4%    €16   10%    0.10 × 0.014 ×  16 = €0.02

(Illustrative example.) The target CRR can differ per page if your margins do — /winter-tyres carries 12% here because the category tolerates a looser efficiency. Everything else is mechanical. You now have a max CPC for every page on the site; the next step is the only judgement call left.

Step 4 — Prioritize: the sort, before and after

A max CPC means nothing on its own. €0.84 is generous in one market and unaffordable in another — what decides is the gap to what a click actually costs you. So pull your real average CPC per page (or per market, if you don’t have page-level) from the Google Ads account and put the two side by side.

Before — the raw join, in whatever order it came out of GA4, is unreadable as a plan:

Page                maxCPC   avg CPC
/sleeping-bags      €0.10    €0.45
/phone-cases        €0.02    €0.35
/cordless-vacuums   €0.84    €0.55
/winter-tyres       €0.67    €0.40

After — sort by headroom (maxCPC − avg CPC) and the same four rows become a work order with the verdict written in the last column:

Landing pageCRAOVTarget CRRmaxCPCavg CPCVerdict
/cordless-vacuums2.0%€42010%€0.84€0.55Build now
/winter-tyres3.1%€18012%€0.67€0.40Build now
/sleeping-bags1.1%€9510%€0.10€0.45Fix first (trouble page)
/phone-cases1.4%€1610%€0.02€0.35Don't bother

(Illustrative example.) The numbers are made up to show the mechanic — plug in your own GA4 figures. Every maxCPC here is just target CRR × CR × AOV applied to the row.

Two rows are obvious. /cordless-vacuums can pay €0.84 against a €0.55 market — +53% headroom, build it. /winter-tyres likewise. /phone-cases can afford €0.02 against €0.35; it will never work in your wettest dreams, leave it out and don’t look back. Scale this from four rows to ten thousand and the top of the sorted list is your TOP 100–200 — the pages to build first, ranked by how much room they have to bid.

The interesting one is /sleeping-bags: maxCPC €0.10 against a €0.45 market. On paper, “don’t bother.” But it had the most sessions in the whole export and a category that obviously should sell. A suspiciously low CR on a page that ought to convert is rarely a demand problem. It’s a trouble page — and trouble pages get a diagnosis, not a delete.

Step 5 — Trouble pages: the diagnosis, on a real listing

When a page’s conversion rate sits far below where the category should land, ask why before you drop it. On e-commerce the answer, most of the time, is the price-competitiveness of the products the page shows first. The first 10–20 products a visitor sees are the page’s entire first impression; if those are your weakest-value items, CR craters regardless of how much demand the page pulls.

So you read the category exactly as the customer does — in its default sort order — and price-check the hero positions.

Read the category's product mix in sort order

Pull the products in /sleeping-bags by their product_type from Google Merchant Center, in the default listing order the visitor actually gets. The top of the list is what’s converting (or not).

Price-check the top positions against the market

Take the top-listed products and research live competitor prices with DataForSEO — the serp/google/organic/live/advanced endpoint returns the whole results page (shopping blocks with merchants and prices, organic) as structured JSON for roughly $0.0035 per query.

Reprice or re-order, then re-measure

If the hero positions are over-priced, you have two levers: reprice, or re-sort the category so genuinely competitive products lead. Then watch CR. Only once it lifts do you promote the page from “trouble” into the build pile.

Here’s what that diagnosis literally looks like on /sleeping-bags, the page sitting at maxCPC €0.10. Top of the listing, your price vs. the cheapest competitor DataForSEO found for the same product:

Pos  Product (first-listed)       Your price  Cheapest comp.  Gap
 1   AlpineLite 200 Down Bag      €129        €99             +30%
 2   TrekWarm Mummy −5°C          €115        €112            +3%
 3   BaseCamp Synthetic XL        €89         €92             −3%
 4   ValleyHike Junior            €45         €47             −4%

(Illustrative example.) The leak is right at the top: the product 12,300 monthly visitors meet first is priced 30% over the cheapest market offer. Everything below it is competitive — but nobody scrolls past a bad first impression. Mini-example, situation → action → result: hero product is 30% over market → drop its price to €105 or re-sort so the competitive BaseCamp and ValleyHike lead → CR recovers toward the category norm → re-run Step 3, the maxCPC climbs off €0.10, and the page graduates into the build pile.

This is the loop most agencies never close, because it crosses a boundary they usually don’t touch. The shop’s job (pricing, merchandising, sort order) and the agency’s job (buying the traffic) are the same optimization loop. Tune one without the other and you’re bidding into a leak.

After the filter: choosing how you buy

Only now — with the build pile in hand — do you pick the how: AI Max, Dynamic Search Ads, classic STAG, or a combination (broad + DSA in one campaign). One campaign or three or five depends on the client and conversion volume — respect the ~30-conversions-per-campaign rule before you split. I’m leaving this choice to you on purpose. The point of the whole pipeline is that you make it after the economics, not before.

Whatever you land on, the rule is the same: a new campaign must never start on bad pages. Weak landing pages drag your target ROAS loose and poison the learning phase. The pre-filter is what keeps the launch pointed only at pages that can pay for themselves — and from there, building the super-structure (crawl data + keyword research per category via the Google Ads API, constructed in waves by category, language and maturity) is its own piece, and it has one.

The part that ties back to the manifesto

Technically, none of this is new. You could have run the GA4 export, the crawl, the price scrape and the join five years ago. But it would have been half a year of bespoke development, and anyone sane would have given up halfway. The reason I’m writing it down now is that with tools like Codex, Claude Code and the current generation of agents, this stopped being a project and became a regular Tuesday workflow — a script you point at an account and let run overnight.

That’s the whole shift, and it’s clearest from both sides at once: the e-shop’s pricing-and-merchandising work and the agency’s advertising work collapse into one loop you can finally tune together. The economics let you close it.

The part you can steal

The part you can steal

# 1) The ceiling on every landing page
maxCPC = target_CRR * CR * AOV
     = CR * AOV / ROAS          # same thing in ROAS form
# e.g. 0.10 * 0.02 * 1000 = €2.00  (10% CRR, 2% CR, €1000 AOV)

# 2) Screaming Frog custom extraction (~3 min, runs in background)
Configuration → Custom → Custom Extraction → Add
• Products on page   XPath:  count(//div[contains(@class,'product-card')])
                     extractor type: Function Value   (count() returns a number)
• H1                 XPath:  //h1                       → Extract Text
• Breadcrumb         XPath:  //nav[@aria-label='breadcrumb']  → Extract Text
Crawl (or List mode on your GA4 URL set) → export → join to GA4 by URL.
Drop any page with < ~3 products as a thin page before you prioritize.
  1. Use Function Value, not Extract Text, for the product count. count() returns a number; the text extractor will swallow it. This is the single most common reason the count column comes back empty.
  2. Adjust the product-card selector to the site. Right-click a product tile → Inspect → grab the stable class. Get this XPath right once and the thin-page filter runs itself.
  3. Filter product detail pages out of the GA4 export first. You’re sizing where to send traffic — category and collection pages — not individual SKUs. Mixing them in skews every AOV and CR you compute.
  4. Diagnose the trouble pages in sort order. Pull the category by product_type in its default listing order and price-check the top positions — the first impression is what converts, not the page average.

FAQ

Why use maxCPC instead of just looking at ROAS targets in Google Ads?

Because Google’s tROAS reacts after you’ve spent money learning. maxCPC is a pre-launch filter: it tells you, before a single click, which pages can mathematically afford to advertise. You use it to decide what to build; you use tROAS to run what you built.

My CR and AOV swing a lot month to month. Doesn't that break the formula?

Use a stable window — 60 to 90 days — and segment by device or market if they differ materially. The formula isn’t meant to be precise to the cent; it sorts pages into build / fix / skip piles. Order-of-magnitude headroom is what you’re after.

Do I really need Screaming Frog, or can AI just write the crawler?

Either works. Screaming Frog with a custom XPath extraction is the no-code route and is genuinely a three-minute setup. A scripted crawler is better if you need the data joined into a pipeline automatically. Pick by whether this is a one-off audit or a repeatable workflow.

What counts as a 'trouble page' versus a page I should just skip?

A skip page has weak economics by nature — low AOV, low intent — so its maxCPC is genuinely tiny and always will be (/phone-cases at €0.02). A trouble page should convert — decent AOV, real demand, lots of sessions — but doesn’t, usually because its first-listed products are over-priced or badly sorted (/sleeping-bags at €0.10). Skip pages you leave out; trouble pages you fix, then re-measure.

Does this only work for e-commerce?

The maxCPC formula works anywhere you have a conversion value — lead gen included, where AOV becomes lead value. The trouble-page diagnosis (Merchant Center product_type, competitor pricing, category sort order) is e-commerce-specific; lead-gen trouble pages need their own diagnosis, usually form friction or offer mismatch.

How does this connect to AI Max and the end of DSA?

It’s upstream of that decision. Whatever campaign type you land on — AI Max, DSA’s successor, classic STAG — it should only ever point at pages that passed this filter. The strategy choice changes how you buy; the economics decide what’s worth buying at all.


CTA: Want the build pile for your site, ranked by what each page can actually afford? Let’s run the filter on your GA4.

The point of all this

Want this level of visibility in your account?

One e-mail. I'll tell you honestly whether it's worth it for your setup.

Get in touch →