# Vercel AI SDK (/docs/vercel-ai-sdk) Wrap the SocialCrawl API in an AI SDK tool so your agent can fetch current public social media data. Documented endpoint caches apply. SocialCrawl has no dedicated AI SDK provider and does not need one. The API is a single authenticated GET request, so you wrap it in a `tool()` and hand it to `generateText`. One tool gives your agent access to 65 platforms. Documented endpoint caches apply. Prefer not to write the tool yourself? An MCP client gets the same access with one command, plus local validation that refuses a bad call before it costs a credit. See [Skills & MCP](/docs/skills-and-mcp.md). ## Prerequisites - Node.js and a TypeScript runner such as `tsx`. - A SocialCrawl API key from [socialcrawl.dev](https://www.socialcrawl.dev), under Dashboard → API Keys. New accounts start with 100 free credits. - A model provider key for whichever model you pass to `generateText`. ## How do I give a Vercel AI SDK agent social media data? ### Install the packages Check the [AI SDK docs](https://ai-sdk.dev/docs) for current versions. ```bash title="Terminal" npm install ai @ai-sdk/anthropic zod ``` ### Define one tool for the whole API Give it a zod `inputSchema` that takes a `platform`, a `resource`, and the endpoint's `params`, then call the REST API inside `execute` with your key in the `x-api-key` header. ```typescript title="TypeScript" // socialcrawl-ai-sdk.ts // Run with: SOCIALCRAWL_API_KEY=sc_... ANTHROPIC_API_KEY=... npx tsx socialcrawl-ai-sdk.ts import { generateText, tool, stepCountIs } from "ai"; import { anthropic } from "@ai-sdk/anthropic"; import { z } from "zod"; const API_KEY = process.env.SOCIALCRAWL_API_KEY; if (!API_KEY) throw new Error("Set SOCIALCRAWL_API_KEY"); const socialcrawl = tool({ description: "Fetch current public social media, commerce, and review data from SocialCrawl; documented endpoint caches apply. " + "Covers TikTok, Instagram, YouTube, LinkedIn, Reddit, Amazon and more. " + "Set `platform` (e.g. 'tiktok'), `resource` (e.g. 'profile'), and `params` " + "(the endpoint's query fields, e.g. { handle: 'charlidamelio' }).", inputSchema: z.object({ platform: z.string().describe("Platform slug, e.g. 'tiktok' or 'youtube'"), resource: z .string() .describe("Endpoint resource, e.g. 'profile' or 'search'"), params: z .record(z.string(), z.union([z.string(), z.number()])) .describe("Query parameters for the endpoint"), }), execute: async ({ platform, resource, params }) => { const url = new URL( `https://www.socialcrawl.dev/v1/${platform}/${resource}`, ); for (const [key, value] of Object.entries(params ?? {})) { url.searchParams.set(key, String(value)); } const res = await fetch(url, { headers: { "x-api-key": API_KEY } }); const json = await res.json(); if (!json.success) { // Hand the model a directive it can act on, not a raw error envelope. return `SocialCrawl error ${json.error.type}: ${json.error.message}. See ${json.error.doc_url}`; } return json.data; }, }); ``` ### Call the model with a step limit ```typescript title="TypeScript" const { text } = await generateText({ model: anthropic("claude-sonnet-5"), tools: { socialcrawl }, // Let the model call the tool, then answer with the result. stopWhen: stepCountIs(5), maxOutputTokens: 1024, prompt: "How many followers does @charlidamelio have on TikTok?", }); console.log(text); ``` The tool uses `inputSchema` (the AI SDK v6 field, not `parameters`) and the call uses `maxOutputTokens` (not `maxTokens`). `stopWhen: stepCountIs(5)` lets the model call the tool and keep going for up to five steps, so a question needing two lookups still resolves. Swap `anthropic("claude-sonnet-5")` for any provider model the AI SDK supports; the tool definition does not change. ## What can the tool call? Every SocialCrawl endpoint shares the same shape: a GET at `/v1/{platform}/{resource}` with query parameters and one `x-api-key` header, returning the same JSON envelope. A single tool that takes `platform`, `resource`, and `params` therefore reaches all 572 endpoints without a new tool per call. | To let the agent do this | Pass | | ---------------------------------- | ---------------------------------------------------------------------- | | Read one profile, post, or listing | `platform: "tiktok"`, `resource: "profile"`, `params: { handle: ... }` | | Search one platform | `platform: "youtube"`, `resource: "search"`, `params: { query: ... }` | | Search many sources at once | `platform: "search"`, `resource: "everywhere"` | | Check the balance before it spends | `platform: "credits"`, `resource: "balance"` | Point the model at the [platform directory](/platforms) or the machine-readable [`llms.txt`](/docs/ai-agents.md) so it knows which values to pass, and it will pick the right endpoint on its own. ## How do I control credit spend? Credits are billed exactly as the REST API bills them: most endpoints are 1 credit, heavier ones 5 or 10, and composite or bundle endpoints carry their own price (`search/everywhere` is a flat 20). Cache hits cost 0 credits, and empty results and upstream errors are auto-refunded. The response envelope includes `credits_remaining`, so you can surface spend to the user or stop on a budget. See [Credits](/docs/credits.md) for how the ledger works. ## Can I stream results into the UI? Yes, for the endpoints that support it. `search/everywhere`, `search/news`, and several Prism composites answer with Server-Sent Events when you send `Accept: text/event-stream`, so you can render partial results while slow sources are still running instead of blocking on a single 20-second envelope. That is a plain SSE stream you consume yourself inside the tool or alongside it. It is not the AI SDK's own `streamText` transport. See [Streaming (SSE)](/docs/streaming.md) for which endpoints stream and what the frames look like. ## Troubleshooting Those are the v5 names. AI SDK v6 uses `inputSchema` on the tool and `maxOutputTokens` on the call, exactly as in the snippet above. `stopWhen` is missing or set to one step, so generation ends on the tool result. `stepCountIs(5)` gives the model room to call the tool and then write the answer. `execute` is returning the raw envelope. Check `json.success` first and return a short directive instead, as the snippet does. See [Errors](/docs/errors.md) for what each `error.type` means. Honour the `Retry-After` response header before retrying, and back off rather than looping. See [Rate limits](/docs/rate-limits.md). Give it the catalogue. [`/llms-full.txt`](/llms-full.txt) is the complete reference, and there is one file per platform. Or use an MCP client, where the server validates the platform, endpoint, and required parameters locally before spending anything. ## Next steps - [LangChain](/docs/langchain.md): The same pattern in that framework. - [Skills & MCP](/docs/skills-and-mcp.md): Skip the DIY tool with a one-line MCP install. - [Streaming (SSE)](/docs/streaming.md): Which endpoints stream and what the frames look like. - [Batch endpoints](/docs/batch.md): Replace a loop of tool calls with one request.