feat(similarweb): add page views tool, fix paid referrals field mismatch (#5354)

* feat(similarweb): add page views tool, fix paid referrals field mismatch

- Add similarweb_page_views tool (Total Page Views, Desktop & Mobile)
- Fix paidReferrals in website overview: API Lite response key is
  literally "paid _referrals" (space before underscore), not caught
  by the existing fallback chain, so it always resolved to null
- Move startDate/endDate/mainDomainOnly to advanced mode

* fix(similarweb): accept both page_views key spellings in page views response

Cursor Bugbot and Greptile both flagged the response field as page_views by
convention, but SimilarWeb's own docs example response uses pages_views for
this specific endpoint. Accept both spellings defensively so the tool works
regardless of which is actually returned.
This commit is contained in:
Waleed
2026-07-02 10:12:53 -07:00
committed by GitHub
parent e7c9a67194
commit 5966e5cf5a
6 changed files with 185 additions and 1 deletions
+6
View File
@@ -26,6 +26,7 @@ export const SimilarwebBlock: BlockConfig = {
{ label: 'Bounce Rate', id: 'similarweb_bounce_rate' },
{ label: 'Pages Per Visit', id: 'similarweb_pages_per_visit' },
{ label: 'Visit Duration (Desktop)', id: 'similarweb_visit_duration' },
{ label: 'Page Views', id: 'similarweb_page_views' },
],
value: () => 'similarweb_website_overview',
},
@@ -88,6 +89,7 @@ export const SimilarwebBlock: BlockConfig = {
title: 'Start Date',
type: 'short-input',
placeholder: 'YYYY-MM (e.g., 2024-01)',
mode: 'advanced',
condition: {
field: 'operation',
value: 'similarweb_website_overview',
@@ -112,6 +114,7 @@ Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no e
title: 'End Date',
type: 'short-input',
placeholder: 'YYYY-MM (e.g., 2024-12)',
mode: 'advanced',
condition: {
field: 'operation',
value: 'similarweb_website_overview',
@@ -134,6 +137,7 @@ Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no e
id: 'mainDomainOnly',
title: 'Main Domain Only',
type: 'switch',
mode: 'advanced',
condition: {
field: 'operation',
value: 'similarweb_website_overview',
@@ -157,6 +161,7 @@ Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no e
'similarweb_bounce_rate',
'similarweb_pages_per_visit',
'similarweb_visit_duration',
'similarweb_page_views',
],
config: {
tool: (params) => params.operation,
@@ -197,6 +202,7 @@ Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no e
bounceRate: { type: 'json', description: 'Bounce rate data over time' },
pagesPerVisit: { type: 'json', description: 'Pages per visit data over time' },
averageVisitDuration: { type: 'json', description: 'Desktop visit duration data over time' },
pageViews: { type: 'json', description: 'Page view data over time' },
},
}
+2
View File
@@ -3198,6 +3198,7 @@ import {
import {
similarwebBounceRateTool,
similarwebPagesPerVisitTool,
similarwebPageViewsTool,
similarwebTrafficVisitsTool,
similarwebVisitDurationTool,
similarwebWebsiteOverviewTool,
@@ -5166,6 +5167,7 @@ export const tools: Record<string, ToolConfig> = {
similarweb_bounce_rate: similarwebBounceRateTool,
similarweb_pages_per_visit: similarwebPagesPerVisitTool,
similarweb_visit_duration: similarwebVisitDurationTool,
similarweb_page_views: similarwebPageViewsTool,
servicenow_create_record: servicenowCreateRecordTool,
servicenow_read_record: servicenowReadRecordTool,
servicenow_update_record: servicenowUpdateRecordTool,
+1
View File
@@ -1,4 +1,5 @@
export { similarwebBounceRateTool } from './bounce_rate'
export { similarwebPageViewsTool } from './page_views'
export { similarwebPagesPerVisitTool } from './pages_per_visit'
export { similarwebTrafficVisitsTool } from './traffic_visits'
export * from './types'
+148
View File
@@ -0,0 +1,148 @@
import type {
SimilarwebPageViewsParams,
SimilarwebPageViewsResponse,
} from '@/tools/similarweb/types'
import type { ToolConfig } from '@/tools/types'
export const similarwebPageViewsTool: ToolConfig<
SimilarwebPageViewsParams,
SimilarwebPageViewsResponse
> = {
id: 'similarweb_page_views',
name: 'SimilarWeb Page Views',
description: 'Get total page views over time (desktop and mobile combined)',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'SimilarWeb API key',
},
domain: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Website domain to analyze (e.g., "example.com" without www or protocol)',
},
country: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'2-letter ISO country code (e.g., "us", "gb", "de") or "world" for worldwide data',
},
granularity: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Data granularity: daily, weekly, or monthly',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date in YYYY-MM format (e.g., "2024-01")',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End date in YYYY-MM format (e.g., "2024-12")',
},
mainDomainOnly: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Exclude subdomains from results',
},
},
request: {
url: (params) => {
const domain = params.domain
?.trim()
.replace(/^(https?:\/\/)?(www\.)?/, '')
.replace(/\/$/, '')
const url = new URL(
`https://api.similarweb.com/v1/website/${domain}/total-traffic-and-engagement/page-views`
)
url.searchParams.set('api_key', params.apiKey?.trim())
url.searchParams.set('country', params.country?.trim() ?? 'world')
url.searchParams.set('granularity', params.granularity ?? 'monthly')
url.searchParams.set('format', 'json')
if (params.startDate) url.searchParams.set('start_date', params.startDate)
if (params.endDate) url.searchParams.set('end_date', params.endDate)
if (params.mainDomainOnly !== undefined)
url.searchParams.set('main_domain_only', String(params.mainDomainOnly))
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message || data.message || 'Failed to get page views')
}
const meta = data.meta ?? {}
const request = meta.request ?? {}
return {
success: true,
output: {
domain: request.domain ?? null,
country: request.country ?? null,
granularity: request.granularity ?? null,
lastUpdated: meta.last_updated ?? null,
// SimilarWeb's own docs example response uses "pages_views" (with the extra "s") for
// this endpoint, unlike its sibling total-traffic-and-engagement endpoints; fall back
// to "page_views" too in case that spelling changes or varies by account.
pageViews:
(data.pages_views ?? data.page_views)?.map(
(p: { date: string; pages_views?: number; page_views?: number }) => ({
date: p.date,
pageViews: p.pages_views ?? p.page_views ?? 0,
})
) ?? [],
},
}
},
outputs: {
domain: {
type: 'string',
description: 'Analyzed domain',
},
country: {
type: 'string',
description: 'Country filter applied',
},
granularity: {
type: 'string',
description: 'Data granularity',
},
lastUpdated: {
type: 'string',
description: 'Data last updated timestamp',
optional: true,
},
pageViews: {
type: 'array',
description: 'Page view data over time',
items: {
type: 'object',
properties: {
date: { type: 'string', description: 'Date (YYYY-MM-DD)' },
pageViews: { type: 'number', description: 'Total page views' },
},
},
},
},
}
+21
View File
@@ -117,6 +117,27 @@ export interface SimilarwebPagesPerVisitResponse extends ToolResponse {
}
}
/**
* Page Views parameters
*/
export interface SimilarwebPageViewsParams extends SimilarwebTimeSeriesParams {}
/**
* Page Views response
*/
export interface SimilarwebPageViewsResponse extends ToolResponse {
output: {
domain: string
country: string
granularity: string
lastUpdated: string | null
pageViews: Array<{
date: string
pageViews: number
}>
}
}
/**
* Average Visit Duration parameters
*/
@@ -116,7 +116,13 @@ export const similarwebWebsiteOverviewTool: ToolConfig<
search: sources.Search ?? sources.search ?? null,
social: sources.Social ?? sources.social ?? null,
mail: sources.Mail ?? sources.mail ?? null,
paidReferrals: sources['Paid Referrals'] ?? sources.paid_referrals ?? null,
paidReferrals:
sources['Paid Referrals'] ??
// SimilarWeb's API Lite response literally uses "paid _referrals" (space before
// the underscore) as the key for this field.
sources['paid _referrals'] ??
sources.paid_referrals ??
null,
},
},
}