Moz
Category: SEO & Research
Integration type: Platform-level API key
External API: Moz JSON-RPC API v2
Purpose
Moz provides domain authority (DA), page authority (PA), and brand authority scores — industry-standard metrics for measuring a website’s relative search engine ranking strength. These scores appear in:
- Report Writer — domain authority trend over time in monthly reports
- Backlink Researcher — filter prospects by DA score (target DA 30–80 for link building)
- Site Auditor — baseline DA in audit report for context
- Dashboard — DA shown on the SEO Performance screen (D4)
Moz is a platform-level integration — one Moz API account serves all tenants. Per-query cost is tracked internally.
Config Structure
Platform config (env vars)
MOZ_ACCESS_ID=mozscape-xxxxxxxxxxxxxxxx # From moz.com → API → Access Credentials
MOZ_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MOZ_API_BASE_URL=https://api.moz.com/jsonrpc # JSON-RPC endpointAuthentication uses HTTP Basic Auth with accessId:secretKey base64-encoded, plus a Unix timestamp and HMAC-SHA1 signed expiry:
function getMozAuthHeader(accessId: string, secretKey: string): string {
const expires = Math.floor(Date.now() / 1000) + 300; // 5-minute window
const signature = crypto
.createHmac('sha1', secretKey)
.update(`${accessId}\n${expires}`)
.digest('base64');
const token = Buffer.from(`${accessId}:${expires}:${signature}`).toString('base64');
return `Basic ${token}`;
}Integration Pattern
Tool layer (packages/tools/src/moz.ts)
Moz API uses JSON-RPC over HTTPS. All requests are POST to the same endpoint with different method values:
class MozTool {
constructor(
private accessId: string,
private secretKey: string,
private baseUrl: string = 'https://api.moz.com/jsonrpc',
) {}
private async call<T>(method: string, params: Record<string, any>): Promise<T> {
const response = await axios.post(
this.baseUrl,
{ jsonrpc: '2.0', id: '1', method, params },
{
headers: {
Authorization: getMozAuthHeader(this.accessId, this.secretKey),
'Content-Type': 'application/json',
'x-moz-token': this.accessId,
},
},
);
if (response.data.error) {
throw new MozApiError(response.data.error.code, response.data.error.message);
}
return response.data.result;
}
async getDomainAuthority(domain: string): Promise<DomainAuthorityResult> {
const result = await this.call<any>('data.site.metrics.fetch.multiple', {
data: [{ site: { query: domain, scope: 'domain' } }],
data_source: 'latest',
group_columns: ['site.query', 'site.scope'],
index_cols: ['site.query'],
metrics: [
'site.domain_authority',
'site.page_authority',
'site.spam_score',
'site.root_domains_to_root_domain', // Number of referring domains
'site.external_links',
],
});
const row = result.results[0];
return {
domain: domain,
domainAuthority: row['site.domain_authority'] ?? 0,
pageAuthority: row['site.page_authority'] ?? 0,
spamScore: row['site.spam_score'] ?? 0,
referringDomains: row['site.root_domains_to_root_domain'] ?? 0,
externalLinks: row['site.external_links'] ?? 0,
};
}
async getBrandAuthority(query: string): Promise<BrandAuthorityResult> {
// Brand Authority is Moz's newer metric measuring overall brand strength in search
const result = await this.call<any>('data.brand.authority.fetch', {
query,
scope: 'domain',
});
return {
brandAuthority: result.brand_authority,
query,
};
}
async getApiQuota(): Promise<QuotaResult> {
const result = await this.call<any>('data.account.limits.fetch', {});
return {
rowsAvailable: result.rows_available,
rowsUsed: result.rows_used,
resetDate: result.reset_date,
};
}
async bulkGetDomainAuthority(domains: string[]): Promise<DomainAuthorityResult[]> {
// Batch up to 25 domains per call (Moz API limit)
const BATCH_SIZE = 25;
const results: DomainAuthorityResult[] = [];
for (let i = 0; i < domains.length; i += BATCH_SIZE) {
const batch = domains.slice(i, i + BATCH_SIZE);
const result = await this.call<any>('data.site.metrics.fetch.multiple', {
data: batch.map(d => ({ site: { query: d, scope: 'domain' } })),
data_source: 'latest',
group_columns: ['site.query'],
index_cols: ['site.query'],
metrics: ['site.domain_authority', 'site.page_authority', 'site.spam_score'],
});
for (const row of result.results) {
results.push({
domain: row['site.query'],
domainAuthority: row['site.domain_authority'] ?? 0,
pageAuthority: row['site.page_authority'] ?? 0,
spamScore: row['site.spam_score'] ?? 0,
});
}
}
return results;
}
async verify(): Promise<void> {
await this.getApiQuota();
}
}Backlink prospect scoring with DA
// Inside backlink-researcher worker — after generating prospects
const domains = prospects.map(p => p.domain);
const daScores = await mozTool.bulkGetDomainAuthority(domains);
const daMap = Object.fromEntries(daScores.map(r => [r.domain, r.domainAuthority]));
const qualified = prospects
.map(p => ({ ...p, da: daMap[p.domain] ?? 0 }))
.filter(p => p.da >= 30 && p.da <= 80); // Sweet spot for link buildingDA vs PA vs Brand Authority
| Metric | Range | What it measures |
|---|---|---|
| Domain Authority (DA) | 1–100 | Entire domain’s search ranking strength |
| Page Authority (PA) | 1–100 | Individual page’s ranking strength |
| Spam Score | 0–100 | Likelihood of penalisation by Google |
| Brand Authority | 0–100 | Overall brand strength in organic search (Moz’s newer metric) |
DA and PA are logarithmic — moving from 20 to 30 is much easier than moving from 70 to 80.
API Row Credits
Moz API usage is metered in row credits. Each domain queried costs 1 row credit. Monthly allocation depends on the Moz API plan. The platform checks the quota via getApiQuota() before bulk operations.
Test Cases
Unit tests (packages/tools/src/moz.test.ts)
| Test | Approach |
|---|---|
getDomainAuthority() builds correct JSON-RPC payload | Mock axios.post; assert method, params.metrics array |
getDomainAuthority() maps result row to typed object | Mock result with site.domain_authority: 45; assert domainAuthority === 45 |
getBrandAuthority() calls correct method | Assert method === 'data.brand.authority.fetch' |
bulkGetDomainAuthority() batches in groups of 25 | Pass 30 domains; assert two API calls (25 + 5) |
| HMAC-SHA1 auth header computed correctly | Assert header format Basic base64(accessId:expires:sig) |
verify() calls getApiQuota | Assert quota endpoint called |
Throws MozApiError on error response | Mock { error: { code: 401, message: 'Unauthorized' } } |
Related
- Ahrefs Provider — backlink data + URL Rating (alternative DA metric)
- SE Ranking Provider — backlinks and trust metrics
- Backlink Researcher Agent — uses DA for prospect scoring
- Report Writer Agent — DA trend in monthly reports