getHashtagAnalytics
Analyze Twitter hashtag performance by tracking metrics like engagement and reach within specified time periods to measure campaign effectiveness.
Instructions
Get analytics for a specific hashtag
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hashtag | Yes | The hashtag to analyze (with or without #) | |
| startTime | No | Start time for the analysis (ISO 8601) | |
| endTime | No | End time for the analysis (ISO 8601) |
Implementation Reference
- src/handlers/search.handlers.ts:60-101 (handler)The core handler function for 'getHashtagAnalytics' that searches for tweets containing the specified hashtag (optionally within a time range), computes aggregate analytics (total tweets, likes, retweets, replies), and returns formatted results. Handles errors including API tier requirements.export const handleHashtagAnalytics: TwitterHandler<HashtagAnalyticsArgs> = async ( client: TwitterClient | null, { hashtag, startTime, endTime }: HashtagAnalyticsArgs ): Promise<HandlerResponse> => { if (!client) { return createMissingTwitterApiKeyResponse('hashtagAnalytics'); } try { const query = `#${hashtag.replace(/^#/, '')}`; const searchResult = await client.v2.search(query, { max_results: 100, 'tweet.fields': 'public_metrics,created_at', start_time: startTime, end_time: endTime }); const tweets = Array.isArray(searchResult.data) ? searchResult.data : []; if (tweets.length === 0) { return createResponse(`No tweets found for hashtag: ${hashtag}`); } const analytics = { totalTweets: tweets.length, totalLikes: tweets.reduce((sum: number, tweet: TweetV2) => sum + (tweet.public_metrics?.like_count || 0), 0), totalRetweets: tweets.reduce((sum: number, tweet: TweetV2) => sum + (tweet.public_metrics?.retweet_count || 0), 0), totalReplies: tweets.reduce((sum: number, tweet: TweetV2) => sum + (tweet.public_metrics?.reply_count || 0), 0) }; return createResponse(`Hashtag Analytics for ${hashtag}:\n${JSON.stringify(analytics, null, 2)}`); } catch (error) { if (error instanceof Error) { if (error.message.includes('400') && error.message.includes('Invalid Request')) { throw new Error(`Hashtag analytics requires Pro tier access ($5,000/month) or higher for search functionality. Current Basic tier ($200/month) does not include recent search API access. Consider upgrading at https://developer.x.com/en/portal/products/pro or use alternative analytics sources.`); } throw new Error(formatTwitterError(error, 'getting hashtag analytics')); } throw error; } };
- src/tools.ts:403-423 (schema)Tool schema definition including description and input schema (hashtag required, startTime/endTime optional ISO 8601 strings) used for MCP tool listing and validation.getHashtagAnalytics: { description: 'Get analytics for a specific hashtag', inputSchema: { type: 'object', properties: { hashtag: { type: 'string', description: 'The hashtag to analyze (with or without #)' }, startTime: { type: 'string', description: 'Start time for the analysis (ISO 8601)' }, endTime: { type: 'string', description: 'End time for the analysis (ISO 8601)' } }, required: ['hashtag'] } },
- src/index.ts:318-326 (registration)Switch case in the main CallToolRequestHandler that registers and dispatches 'getHashtagAnalytics' calls to the handleHashtagAnalytics function.case 'getHashtagAnalytics': { const { hashtag, startTime, endTime } = request.params.arguments as { hashtag: string; startTime?: string; endTime?: string; }; response = await handleHashtagAnalytics(client, { hashtag, startTime, endTime }); break; }
- src/types.ts:117-121 (schema)TypeScript interface defining input arguments for getHashtagAnalytics (note: slightly differs from runtime schema; possibly legacy or additional).export interface GetHashtagAnalyticsArgs { hashtag: string; maxResults?: number; tweetFields?: string[]; }
- src/types.ts:491-514 (schema)Runtime type assertion function for validating getHashtagAnalytics arguments.export function assertGetHashtagAnalyticsArgs(args: unknown): asserts args is GetHashtagAnalyticsArgs { if (typeof args !== 'object' || args === null) { throw new Error('Invalid arguments: expected object'); } if (!('hashtag' in args) || typeof (args as any).hashtag !== 'string') { throw new Error('Invalid arguments: expected hashtag string'); } if ('maxResults' in args) { const maxResults = (args as any).maxResults; if (typeof maxResults !== 'number' || maxResults < 10 || maxResults > 100) { throw new Error('Invalid arguments: maxResults must be a number between 10 and 100'); } } if ('tweetFields' in args) { if (!Array.isArray((args as any).tweetFields)) { throw new Error('Invalid arguments: expected tweetFields to be an array'); } for (const field of (args as any).tweetFields) { if (typeof field !== 'string') { throw new Error('Invalid arguments: expected tweetFields to be an array of strings'); } } } }