Backlinks counter for a SaaS dashboard, step by step
A working counter needs one server route and one small component. This guide builds both, with the failure states most first versions forget.
AlfaLinks editorial team ·
Scope of this guide
We assume a Node or Python backend and any front-end framework. Every request below hits the documented API, and the base URL is your brand's own: alfalinks.net/api.php.
Five steps, in the order we would ship them
1
1. Create the key and store it as a secret
Sign in with Google at /auth/google.php, copy the sk_ key from the account page and put it in your server environment. The front end never sees it.
2
2. Add one proxy route
Expose something like /internal/links?domain=... that validates the domain, calls our API, and returns only the fields your UI uses. Validation matters because users type anything.
3
3. Start with the free action
The overview action costs nothing, so the first version of the counter has no billing risk at all. Move to paid actions when a screen needs them.
4
4. Render three states
Loading, data, and unavailable. Unavailable covers HTTP 401, HTTP 402 and a network failure, and it should never show a zero.
5
5. Add the freshness label
Our index refreshes roughly monthly. A grey line reading 'link data updated monthly' prevents the support ticket that begins 'I added a link yesterday'.
The proxy route, in Node
Short enough to read in one screen. The cache is a plain Map here; swap in Redis once you run more than one process.
js
const cache = new Map();
const MONTH = 30 * 24 * 3600 * 1000;
app.get('/internal/links', async (req, res) => {
const domain = String(req.query.domain || '').toLowerCase().trim();
if (!/^[a-z0-9.-]+\.[a-z]{2,}$/.test(domain)) return res.status(400).json({ok:false});
const hit = cache.get(domain);
if (hit && Date.now() - hit.t < MONTH) return res.json(hit.v);
const r = await fetch(`https://alfalinks.net/api.php?action=overview&q=${domain}`);
if (!r.ok) return res.status(502).json({ok:false});
const v = await r.json();
cache.set(domain, {t: Date.now(), v});
res.json(v);
});
Adding a DR badge once the counter works
The counter is the easy half. The badge needs one extra call.
For a table of customer domains, send a single bulk_dr request with up to 2,000 domains instead of one call per row. It costs 1 credit whatever the row count, and the response maps each domain to its 0-100 figure, which you store beside the cached overview.
Match domains on the normalised hostname. Strip the scheme, the path and a leading www, or half your rows will miss the lookup and show blanks.
Test the unhappy paths first. Happy paths test themselves.
Revoke the key in staging and confirm the card shows 'unavailable' rather than zero, then drain a test balance to trigger a 402, and paste a malformed domain such as 'http://' to prove the validator rejects it before any credit is spent.
A short smoke test belongs in CI. One free overview call on nytimes.com, run nightly, tells you the route and the key still work.
What the counter should say, and what it should not
Say less than you know. A counter labelled 'backlinks' invites the question 'why does Ahrefs show a different number?', and the honest answer is that two crawlers see two slices of the web.
Label the figure with its source and month instead. Something like 'Referring domains, AlfaLinks index, October 2026' is longer, but it ends the argument before it starts and it reads fine in a small card.
Round for display. A user who sees 12,481 on Monday and 12,481 on Friday trusts the tool more than one who sees jitter, and our monthly refresh gives you that stability for free.
If you want the 0-100 figure next to it, read the notes on a backlinks score first. It is our own metric, so naming matters.
Failure states and what the UI does
HTTP codes are the ones the API returns; the UI column is our suggestion.