Skip to content

adsense ​

The adsense plugin reports Google AdSense earnings for one account. It sends today, yesterday, the last 7 days, month to date and 7-day page RPM, plus a 30-day daily series and a per-site breakdown. It warns when an account that was earning makes nothing for a full day, which is how broken ad tags, a bad ads.txt or a policy stop show up.

Set it up ​

AdSense has no service-account access. The plugin runs on a user refresh token with the adsense.readonly scope, minted once by hand.

  1. In Google Cloud, create an OAuth client of type Desktop app and download its JSON.

  2. Enable the AdSense Management API in that project.

  3. Set the OAuth consent screen to In production, or Internal. A client left in Testing hands out refresh tokens that expire after 7 days.

  4. From the client directory, run the token helper.

    bash
    node etc/google-auth.mjs --source=adsense <client_secret.json> [ssh-host] [remote-config-path]

    --source defaults to adsense. The helper opens Google's consent page, catches the redirect on a loopback port and trades the code for a refresh token. Before it saves, it checks that the token can see at least one AdSense account. With no ssh-host it writes the adsense block into ./client.config.json. With one, it writes into that host's config over ssh and sends the secrets on stdin.

  5. Add adsense to the agent's plugins array and restart the agent.

The Google account you consent with must have access to the AdSense account.

json
{
  "plugins": ["adsense"],
  "adsense": {
    "name": "AdSense",
    "uniqueId": "adsense",
    "refreshInterval": 900000,
    "clientId": "<CLIENT_ID>.apps.googleusercontent.com",
    "clientSecret": "<CLIENT_SECRET>",
    "refreshToken": "<REFRESH_TOKEN>",
    "accountId": "accounts/pub-<PUBLISHER_ID>"
  }
}
OptionDefaultWhat it does
clientIdrequiredOAuth client id.
clientSecretrequiredOAuth client secret.
refreshTokenrequiredRefresh token from google-auth.mjs.
accountIdfirst accountaccounts/pub-.... Only needed when the token can see more than one AdSense account.
refreshInterval900000Milliseconds between reports.
timeout15000Milliseconds per HTTP request.

What it reports ​

One report per interval, sent immediately on start. Each poll pulls one report of earnings, page views and clicks per day. It starts at whichever is earlier, the 1st of the month or 29 days ago, and runs through today. Every figure is summed from those rows, so they cannot disagree with each other.

  • name, the account's display name when AdSense gives one. It replaces the plugin's own name.
  • accountId, currency and asOf, today's date in the account's time zone.
  • today, yesterday, last7 and monthToDate earnings. last7 includes today, as AdSense's own "Last 7 days" does.
  • pageViews7, clicks7 and rpm, which is earnings per thousand page views over the same 7 days.
  • daily, 30 entries of { date, earnings, pageViews, clicks }, oldest first, gap-filled with zeroes.
  • sites[], up to 20 domains, biggest earner first. Each has the same totals plus daily earnings. A leading www. is merged into the bare domain. Domains that earned nothing in the window are dropped.
  • When the poll fails, the report is { error }, plus authExpired: true if Google answered invalid_grant.

Dates are in the account's time zone, not the agent host's.

The server does not write a history row per report. The type is in SELF_HISTORIED, because each report already carries 30 days.

When it alerts ​

ConditionSeverityReason text
authExpirederror<name>: authorization expired, mint a new refresh token
errorerror<name>: <error>
clientId, clientSecret or refreshToken missingerrorAdSense: adsense plugin needs clientId, clientSecret and refreshToken
yesterday is 0 and the 7-day total minus today and yesterday is above 0warning<name>: no earnings yesterday

The server judges yesterday, not today, because today's figure starts at zero and fills in hours late. Only a full zero day trips the warning. A partial drop, even 80%, does not.

A new problem does not notify on the first bad report. The server waits for a second consecutive bad report, which is 15 minutes later at the default interval. A clean report resolves the alert.

On the dashboard ​

The card takes the account's display name, labelled Google AdSense.

ReadingSourceWarn
TODAYtodaynone
YESTERDAYyesterdaywhen it is 0
7 DAYSlast7none
MONTHmonthToDatenone
PAGE RPMrpmnone

Amounts use the report's currency. The sparkline is the 30 daily earnings figures. While the report carries an error, the figures blank out rather than showing zeroes that would read as "earned nothing". The card links to AdSense.

The card goes OFFLINE after 1800 seconds without a report, which is two missed polls at the default interval.

Gotchas ​

  • The agent looks up the account and its time zone once and keeps them until restart. Restart the agent after changing accountId.
  • The YESTERDAY tile turns amber on any zero day, even for an account that never earned. The server only warns when earlier days in the week earned something.
  • The per-site report is optional. If it fails, the totals still report and sites is empty.
  • Refresh tokens from a consent screen in Testing die after 7 days, and the card turns red with authorization expired. Run google-auth.mjs again with the app set to In production.
  • client.config.json.example sets refreshInterval to 600000. The plugin default and the helper both use 900000.