Appearance
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.
In Google Cloud, create an OAuth client of type Desktop app and download its JSON.
Enable the AdSense Management API in that project.
Set the OAuth consent screen to In production, or Internal. A client left in Testing hands out refresh tokens that expire after 7 days.
From the
clientdirectory, run the token helper.bashnode etc/google-auth.mjs --source=adsense <client_secret.json> [ssh-host] [remote-config-path]--sourcedefaults toadsense. 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 nossh-hostit writes theadsenseblock into./client.config.json. With one, it writes into that host's config over ssh and sends the secrets on stdin.Add
adsenseto the agent'spluginsarray 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>"
}
}| Option | Default | What it does |
|---|---|---|
clientId | required | OAuth client id. |
clientSecret | required | OAuth client secret. |
refreshToken | required | Refresh token from google-auth.mjs. |
accountId | first account | accounts/pub-.... Only needed when the token can see more than one AdSense account. |
refreshInterval | 900000 | Milliseconds between reports. |
timeout | 15000 | Milliseconds 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,currencyandasOf, today's date in the account's time zone.today,yesterday,last7andmonthToDateearnings.last7includes today, as AdSense's own "Last 7 days" does.pageViews7,clicks7andrpm, 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 plusdailyearnings. A leadingwww.is merged into the bare domain. Domains that earned nothing in the window are dropped.- When the poll fails, the report is
{ error }, plusauthExpired: trueif Google answeredinvalid_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
| Condition | Severity | Reason text |
|---|---|---|
authExpired | error | <name>: authorization expired, mint a new refresh token |
error | error | <name>: <error> |
clientId, clientSecret or refreshToken missing | error | AdSense: adsense plugin needs clientId, clientSecret and refreshToken |
yesterday is 0 and the 7-day total minus today and yesterday is above 0 | warning | <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.
| Reading | Source | Warn |
|---|---|---|
| TODAY | today | none |
| YESTERDAY | yesterday | when it is 0 |
| 7 DAYS | last7 | none |
| MONTH | monthToDate | none |
| PAGE RPM | rpm | none |
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
sitesis empty. - Refresh tokens from a consent screen in Testing die after 7 days, and the card turns red with
authorization expired. Rungoogle-auth.mjsagain with the app set to In production. client.config.json.examplesetsrefreshIntervalto600000. The plugin default and the helper both use900000.