enhanced_search_analytics
Analyze Google Search Console data with advanced filtering, regex matching, and quick wins detection to identify optimization opportunities.
Instructions
Enhanced search analytics with up to 25,000 rows, regex filters, and quick wins detection
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| siteUrl | Yes | The site URL as defined in Search Console. Example: sc-domain:example.com (for domain resources) or http://www.example.com/ (for site prefix resources) | |
| startDate | Yes | Start date in YYYY-MM-DD format | |
| endDate | Yes | End date in YYYY-MM-DD format | |
| dimensions | No | Comma-separated list of dimensions to break down results by, such as query, page, country, device, searchAppearance | |
| type | No | Type of search to filter by, such as web, image, video, news | |
| aggregationType | No | Type of aggregation, such as auto, byNewsShowcasePanel, byProperty, byPage | |
| rowLimit | No | Maximum number of rows to return (up to 25,000 for enhanced performance) | |
| pageFilter | No | Filter by a specific page URL. Use with filterOperator. | |
| queryFilter | No | Filter by a specific query string. Use with filterOperator. | |
| countryFilter | No | Filter by a country using ISO 3166-1 alpha-3 code (e.g., USA, CHN). | |
| deviceFilter | No | Filter by device type. | |
| filterOperator | No | Operator for page and query filters. Defaults to "equals". Enhanced with regex support. | equals |
| regexFilter | No | Advanced regex filter for intelligent query matching | |
| enableQuickWins | No | Enable automatic quick wins detection | |
| quickWinsThresholds | No | Custom thresholds for quick wins detection |
Implementation Reference
- src/search-console.ts:74-129 (handler)Main handler function implementing the enhanced search analytics tool logic, supporting up to 25k rows, regex filtering, and quick wins detection.async enhancedSearchAnalytics( siteUrl: string, requestBody: SearchanalyticsQueryRequest, options: { regexFilter?: string; enableQuickWins?: boolean; quickWinsThresholds?: { minImpressions?: number; maxCtr?: number; positionRangeMin?: number; positionRangeMax?: number; }; } = {} ) { // Ensure requestBody is defined if (!requestBody) { throw new Error('Request body is required'); } // Apply regex filter if provided if (options.regexFilter && requestBody.dimensions?.includes('query')) { requestBody.dimensionFilterGroups = [ ...(requestBody.dimensionFilterGroups || []), { groupType: 'and', filters: [{ dimension: 'query', operator: 'includingRegex', expression: options.regexFilter }] } ]; } // Execute enhanced search analytics const result = await this.searchAnalytics(siteUrl, requestBody); // Apply quick wins detection if enabled if (options.enableQuickWins && result.data.rows) { const quickWins = this.detectQuickWins(result.data.rows, options.quickWinsThresholds); return { ...result, data: { ...result.data, quickWins: quickWins, enhancedFeatures: { regexFilterApplied: !!options.regexFilter, quickWinsEnabled: true, rowLimit: requestBody.rowLimit || 1000 } } }; } return result; }
- src/search-console.ts:135-187 (helper)Supporting utility for detecting SEO quick wins based on search analytics data.private detectQuickWins( rows: any[], thresholds: { minImpressions?: number; maxCtr?: number; positionRangeMin?: number; positionRangeMax?: number; } = {} ) { const { minImpressions = 50, maxCtr = 2.0, positionRangeMin = 4, positionRangeMax = 10 } = thresholds; return rows .filter(row => { const impressions = row.impressions || 0; const ctr = (row.ctr || 0) * 100; const position = row.position || 0; return impressions >= minImpressions && ctr <= maxCtr && position >= positionRangeMin && position <= positionRangeMax; }) .map(row => { const impressions = row.impressions || 0; const currentClicks = row.clicks || 0; const currentCtr = (row.ctr || 0) * 100; const position = row.position || 0; // Calculate potential with 5% target CTR const targetCtr = 5.0; const potentialClicks = Math.round((impressions * targetCtr) / 100); const additionalClicks = Math.max(0, potentialClicks - currentClicks); return { query: row.keys?.[0] || 'N/A', page: row.keys?.[1] || 'N/A', currentPosition: Number(position.toFixed(1)), impressions: impressions, currentClicks: currentClicks, currentCtr: Number(currentCtr.toFixed(2)), potentialClicks: potentialClicks, additionalClicks: additionalClicks, opportunity: additionalClicks > 0 ? 'High' : 'Low', optimizationNote: `Move from position ${position.toFixed(1)} to improve CTR` }; }) .sort((a, b) => b.additionalClicks - a.additionalClicks); }
- src/schemas.ts:106-117 (schema)Zod schema defining inputs for the enhanced_search_analytics tool, extending base search analytics with quick wins options.export const EnhancedSearchAnalyticsSchema = SearchAnalyticsSchema.extend({ enableQuickWins: z.boolean().default(false).describe('Enable automatic quick wins detection'), quickWinsThresholds: QuickWinsDetectionSchema.pick({ minImpressions: true, maxCtr: true, positionRangeMin: true, positionRangeMax: true, }).optional().describe('Custom thresholds for quick wins detection'), }); export type SearchAnalytics = z.infer<typeof SearchAnalyticsSchema>; export type EnhancedSearchAnalytics = z.infer<typeof EnhancedSearchAnalyticsSchema>;
- src/index.ts:54-57 (registration)Tool registration in MCP server's listTools handler, specifying name, description, and input schema.name: 'enhanced_search_analytics', description: 'Enhanced search analytics with up to 25,000 rows, regex filters, and quick wins detection', inputSchema: zodToJsonSchema(EnhancedSearchAnalyticsSchema), },
- src/index.ts:96-161 (handler)MCP server handler for calling the enhanced_search_analytics tool, parsing arguments and invoking the service implementation.case 'enhanced_search_analytics': { const args = EnhancedSearchAnalyticsSchema.parse(request.params.arguments); const siteUrl = args.siteUrl; // Build enhanced request body const requestBody: any = { startDate: args.startDate, endDate: args.endDate, dimensions: args.dimensions, searchType: args.type, aggregationType: args.aggregationType, rowLimit: args.rowLimit, // Up to 25,000! }; // Build filters (including regex support) const filters = []; if (args.pageFilter) { filters.push({ dimension: 'page', operator: args.filterOperator, expression: args.pageFilter, }); } if (args.queryFilter) { filters.push({ dimension: 'query', operator: args.filterOperator, expression: args.queryFilter, }); } if (args.countryFilter) { filters.push({ dimension: 'country', operator: 'equals', expression: args.countryFilter, }); } if (args.deviceFilter) { filters.push({ dimension: 'device', operator: 'equals', expression: args.deviceFilter, }); } if (filters.length > 0) { requestBody.dimensionFilterGroups = [{ groupType: 'and', filters }]; } // Call enhanced search analytics const enhancedOptions = { regexFilter: args.regexFilter, enableQuickWins: args.enableQuickWins, quickWinsThresholds: args.quickWinsThresholds, }; const response = await searchConsole.enhancedSearchAnalytics(siteUrl, requestBody, enhancedOptions); return { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; }