All work

Software company, business to business

The ads were counting sign-ups that were never confirmed. We changed what counted.

$1.72

Cost per confirmed account

total spend divided by confirmed accounts

204

Confirmed accounts

email address confirmed by the person who signed up

2.65%

Click-through rate on the ads

as reported by the ad platform

Role

Website build, tracking and paid campaigns

Reading time

7 min read

Tools

Next.jsGA4Google Tag ManagerServer-side trackingMeta Conversions APIConsent Mode v2

This client sells software with a free tier and was running paid social ads to get sign-ups. The ads were set to count a sign-up the moment the form was submitted, but a share of those people never confirmed their email address, so the accounts were not usable. We rebuilt the site and changed what the ad platform counted as a result, so it only counted people who confirmed. Over the campaign, 204 people created confirmed accounts, at an average cost of $1.72 each.

Background

Ad platforms decide who to show your ads to by learning from the results you report back to them. If you tell the platform that a result is someone submitting a form, it will go and find more people who submit forms. If you tell it that a result is someone creating a confirmed account, it will find more people who do that instead.

That makes the choice of what counts as a result one of the most important decisions in a paid campaign, and it is easy to get wrong without noticing. The ad platform's own dashboard will always look reasonable, because it reports exactly what it was told to count.

The gap only becomes visible when someone compares the number of conversions in the ad account against the number of usable accounts in the product. That was the question this client wanted answered before committing more budget.

The problem

  • The sign-up was counted too early

    It was recorded the moment the form was submitted, before the person confirmed their email address, so email addresses that were never confirmed were being treated as results.

  • Nothing linked the ad to what happened next

    There was no connection between a campaign and whether the person went on to use the product, so there was no way to tell which campaigns brought people who stayed.

  • The record was made in the browser only

    Ad blockers and browser privacy settings removed a share of it. The share removed is not spread evenly, so it skews any comparison between campaigns.

  • The only reporting was the ad platform's own

    Creative decisions were being made on the platform's numbers, with nothing independent to check them against.

Constraints we worked within

  • No data team

    Anything built had to be maintainable afterwards by one person, without specialist knowledge.

  • Visitors in the EU

    Consent had to properly control what ran in the browser, not be worked around.

  • No data warehouse

    Reporting had to arrive in tools the client already used.

  • The site was being rebuilt at the same time

    This was the useful part. The measurement could be designed alongside the pages instead of added afterwards.

Approach, and the cheaper option we did not take

The cheaper route is to leave the browser tracking as it is and upload a file of confirmed accounts once a day. It needs no server, there is less to maintain, and it does technically fix the counting problem.

We chose to send the events from a server instead, because of the delay. With a daily upload, the ad platform is learning from results that are at least a day old. That delay matters most in the first days of a campaign, which is exactly when the budget is being spent least efficiently.

So the setup became: one definition of a confirmed account, sent to both the analytics and the ad platform, matched against the browser record so nothing was counted twice, and delivered within seconds rather than the next day.

What we built

Step 01

Define the events before building the pages

We wrote down the list of events first and built the site against it. Because the site build was running at the same time, the tracking was designed into the pages rather than fitted on afterwards, which is what keeps it working when pages change later.

sign_up_submittedsign_up_confirmedfirst_use

Step 02

Set up a server to receive the events

Events go from the browser to a server we run, and that server passes them on to the analytics and the ad platform. The browser tracking stays in place as well, and both copies carry the same reference number so the ad platform treats them as one result rather than two.

Step 03

Make confirmation the thing that counts

The result reported to the ad platform became the confirmed account rather than the submitted form, sent at the moment the person clicks the link in their confirmation email. Unconfirmed sign-ups stopped influencing who the ads were shown to.

Step 04

Handle consent properly

Consent Mode v2 was set up so that visitors in the EU who decline are estimated rather than simply missing. Contact details sent to the ad platform are scrambled first, which is what lets the platform match a sale to a click without receiving readable personal data.

Step 05

Report on the number that matters

Reports were built around campaign and creative, showing cost per confirmed account. That became the number on screen during every campaign review.

How the data moves

BrowserConfirmationConsent checkA server we runYour analyticsAd platform
  • The browser passes through a consent check before anything is sent.
  • The confirmation service reports a confirmed account straight to our server.
  • One definition leaves that server and reaches both destinations, carrying the same reference number in each copy.
One definition leaves the server and reaches both destinations, so the reports and the ad bidding read the same result.

Results

204confirmed accounts
name, email address, confirmation completed
$1.72average cost per confirmed account
2.65%click-through rate on the ads

Budget was moved continuously toward the ads producing confirmed accounts rather than the ads producing the cheapest form submissions.

What counted as a result, before

  • Recorded on form submit, in the browser
  • Included email addresses never confirmed
  • Reduced by ad blockers and browser privacy settings

What counted as a result, after

  • Recorded on a server, when confirmation completes
  • Counts confirmed accounts only
  • Matched against the browser copy so nothing is double counted

How this was measured

Confirmed accounts were counted from the client's own database rather than from the ad platform. Cost per confirmed account is total spend divided by confirmed accounts over the same period. The click-through rate is the ad platform's own figure. Anonymised reporting is available on request.

What we would do differently

We would have defined the first-use event at the same time as the confirmation event, rather than adding it once the rest was already running. A confirmed email address proves the address is real. First use proves the product was worth opening. Having both from the start would have given the campaigns a better signal several weeks sooner.

What this means for you

If you run ads to a product that has a sign-up step and then a separate first-use step, and you cannot currently say which campaign produced people who actually used it, this is the same situation. It is usually a measurement question rather than a creative one, and testing new ads before it is settled gives you less to learn from than it should.

This was real client work. The client's name and identifying details are withheld under a confidentiality agreement. Anonymised reports and documentation are available on request.

Is your ad platform counting the right thing?

Send a few lines about your setup and we will reply with what we would look at first.

Tell us about your project