How it works

Four moving parts.

Collection, attribution, spend, and the join between them. None of it needs to know who anyone is.
A pear character walking briskly with a folder under one arm.

01 · Collection

A pear character reading an open book.

One script, served from your own subdomain.

You add an A record pointing a subdomain of your site at the tracker host, and one deferred script tag. Because the script comes from your own domain rather than a known analytics host, blockers that work by blocking third-party analytics domains never see it.

Sessions are counted with a rotating server-side hash of connection data. The salt rotates daily, so the same visitor tomorrow is a new session with no way to connect it to today.

  • Nothing is written to the device. No cookie, no localStorage, no sessionStorage.
  • The IP address is used in memory to compute the hash and is never stored.
  • No identifier survives the day. There is no key that connects a session today to a session tomorrow.

Installation, step by step

The whole install2 lines
One DNS record
metrics.pearmetrics.com A 203.0.113.10
One script tag
<script defer src="https://metrics.pearmetrics.com/p.js" data-site="b6c9e2a1"></script>

02 · Attribution

Last non-direct click, session-scoped.

A pear character weighing something up, palms held like scales.

Traffic is attributed on the UTM triple (source, medium, campaign), read from the landing URL at the first event of a session. Later events in the same session are same-site navigations, and their UTMs are ignored so they can’t overwrite the real acquisition source with noise.

03 · Spend

Daily, at campaign level, from both platforms.

Every morning the sync pulls campaign spend, impressions and clicks from the Google Ads and Meta APIs. Money and clicks only. Nothing user-level is ever requested from an ad platform, which is what keeps the privacy posture whole rather than merely front-facing.

Each run re-pulls a trailing seven-day window and overwrites, because both platforms restate recent days after the fact. A same-day-only pull would lock in whatever figure happened to be visible the moment the job ran. It also means a missed run heals itself: the next one restates the days the missed one would have written.

Daily spendLast 30 daysGoogle Ads $9,593Meta $6,146

Figures shown are illustrative.

Two things that quietly corrupt the numbers.

Timezone

Sessions in UTC, spend in the account’s day.

Joined naively, up to eight hours of every day’s sessions sit against the wrong day’s spend, and the totals still look plausible. You set one reporting timezone per site, each account’s timezone is read from the platform rather than typed, and a mismatch raises a warning instead of being silently reconciled.

Currency

One currency per site, or the sync refuses.

All ad accounts on a site must share one currency. If they don’t, the sync refuses to run rather than converting at a rate nobody checked. A wrong rate is worse than a refused sync, because it produces a plausible number nobody questions.

04 · The join

A pear character gesturing to one side with an open palm.

Campaign spend meets sessions on the UTM triple.

A mapping table ties one platform campaign to one UTM triple. Matching campaign names against utm_campaign at query time would need less setup and would break the first time somebody renames a campaign in the ad platform, which happens constantly and silently. A mapping row survives the rename; a string comparison does not.

Because click IDs are dropped, manual tagging carries the attribution. If a campaign ships untagged, its clicks land as direct and its spend sits unmatched. So the product tells you, rather than hiding it in an average. Without that panel the tool reports confidently wrong CPAs, which is worse than no tool at all.

What the health panel checks

Money

Unmatched spend.

Money with no session behind it. Tagging is broken, or a campaign is new.

Traffic

Unmatched paid sessions.

Paid-looking traffic with no spend behind it. A mapping gap, or a typo in a tagging template.

Naming

Unclassified traffic.

Source and medium combinations matching no channel rule. Almost always a typo, and invisible everywhere else.

Tagging healthLast 30 days

Click IDs are stripped at ingest and never stored, so tagging is load-bearing: an untagged campaign lands as direct traffic with unmatched spend.

Some spend is missing its pair.

Usually a tagging gap. $412.80 (2.6% of total spend) has no mapped UTM triple. Here is where.

  • Performance Max - Q3 Test (Google Ads · 284-991-0043)$268.40
  • Advantage+ Catalogue (Meta · act_1099238471)$144.40

Unmatched paid sessions

414 paid-looking sessions have no spend mapped to them. Usually a mapping gap, or a typo in a tagging template.

  • facebook / paid_social / summer-promo318
  • google / cpc / (not set)96

Unclassified traffic

Source and medium combinations matching no channel rule. Almost always a typo, and invisible everywhere else.

  • newsletter / e-mail611
  • facebook / Paid_Social204

Figures shown are illustrative.

Custom events

One call.

Mark any event you send as a conversion and it becomes the denominator of every CPA in the table. Shopify purchase tracking runs through a checkout-safe custom pixel, documented in full.

Custom events · Shopify

A conversion1 line
pear.track('signup', { plan: 'pro' })

Four parts.
About ten minutes.

A pear character celebrating with both arms in the air.