|
| 1 | +--- |
| 2 | +title: "Smart Spreadsheet" |
| 3 | +sidebarTitle: "Smart Spreadsheet" |
| 4 | +description: "An AI-powered company enrichment tool that uses Exa search and Claude to extract verified company data with source attribution." |
| 5 | +--- |
| 6 | + |
| 7 | +import RealtimeLearnMore from "/snippets/realtime-learn-more.mdx"; |
| 8 | + |
| 9 | +## Overview |
| 10 | + |
| 11 | +Smart Spreadsheet is an AI-powered tool that enriches company data on demand. Input a company name or website URL and get verified information including industry, headcount, and funding details; each with source attribution. Results appear in the frontend in real-time as each task completes. |
| 12 | + |
| 13 | +- A [Next.js](https://nextjs.org/) app with [Trigger.dev](https://trigger.dev/) for background tasks |
| 14 | +- [Exa](https://exa.ai/) – an AI-native search engine that returns clean, structured content ready for LLM extraction |
| 15 | +- [Claude](https://anthropic.com/) via the [Vercel AI SDK](https://sdk.vercel.ai/) for data extraction |
| 16 | +- [Supabase](https://supabase.com/) PostgreSQL database for persistence |
| 17 | +- Trigger.dev [Realtime](/realtime/overview) for live updates to the frontend |
| 18 | + |
| 19 | +## Video |
| 20 | + |
| 21 | +<video |
| 22 | + controls |
| 23 | + className="w-full aspect-video" |
| 24 | + src="https://content.trigger.dev/smart-spreadsheet.mp4" |
| 25 | +></video> |
| 26 | + |
| 27 | +## GitHub repo |
| 28 | + |
| 29 | +<Card |
| 30 | + title="View the Smart Spreadsheet repo" |
| 31 | + icon="github" |
| 32 | + href="https://github.com/triggerdotdev/examples/tree/main/smart-spreadsheet" |
| 33 | +> |
| 34 | + Click here to view the full code for this project in our examples repository on GitHub. You can |
| 35 | + fork it and use it as a starting point for your own project. |
| 36 | +</Card> |
| 37 | + |
| 38 | +## How it works |
| 39 | + |
| 40 | +The enrichment workflow: |
| 41 | + |
| 42 | +1. **Trigger enrichment** – User enters a company name or URL in the spreadsheet UI |
| 43 | +2. **Parallel data gathering** – Four subtasks run concurrently to fetch basic info, industry, employee count, and funding details |
| 44 | +3. **AI extraction** – Each subtask uses Exa search + Claude to extract structured data with source URLs |
| 45 | +4. **Real-time updates** – Results appear in the frontend as each subtask completes |
| 46 | +5. **Persist results** – Enriched data is saved to Supabase with source attribution |
| 47 | + |
| 48 | +## Features |
| 49 | + |
| 50 | +- **Parallel processing** – All four enrichment categories run simultaneously using [batch.triggerByTaskAndWait](/triggering#batch-trigger-by-task-and-wait) |
| 51 | +- **Source attribution** – Every data point includes the URL it was extracted from |
| 52 | +- **Live updates** – Results appear in the UI as each task completes using [Realtime](/realtime/overview) |
| 53 | +- **Structured extraction** – Zod schemas ensure consistent data output from Claude |
| 54 | + |
| 55 | +## Key code patterns |
| 56 | + |
| 57 | +### Parallel task execution |
| 58 | + |
| 59 | +The main task triggers all four enrichment subtasks simultaneously using `batch.triggerByTaskAndWait`: |
| 60 | + |
| 61 | +```ts src/trigger/enrich-company.ts |
| 62 | +const { runs } = await batch.triggerByTaskAndWait([ |
| 63 | + { task: getBasicInfo, payload: { companyName, companyUrl } }, |
| 64 | + { task: getIndustry, payload: { companyName, companyUrl } }, |
| 65 | + { task: getEmployeeCount, payload: { companyName, companyUrl } }, |
| 66 | + { task: getFundingRound, payload: { companyName, companyUrl } }, |
| 67 | +]); |
| 68 | +``` |
| 69 | + |
| 70 | +### Live updates from child tasks |
| 71 | + |
| 72 | +Each subtask uses `metadata.parent.set()` to update the parent's metadata as soon as data is extracted: |
| 73 | + |
| 74 | +```ts src/trigger/get-basic-info.ts |
| 75 | +// After Claude extracts the data, update the parent task's metadata |
| 76 | +metadata.parent.set("website", object.website); |
| 77 | +metadata.parent.set("description", object.description); |
| 78 | +``` |
| 79 | + |
| 80 | +The frontend subscribes to these metadata updates using [Realtime](/realtime/overview), so users see each field populate as it's discovered. |
| 81 | + |
| 82 | +## Relevant code |
| 83 | + |
| 84 | +| File | Description | |
| 85 | +| ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | |
| 86 | +| [`src/trigger/enrich-company.ts`](https://github.com/triggerdotdev/examples/blob/main/smart-spreadsheet/src/trigger/enrich-company.ts) | Main orchestrator that triggers parallel subtasks and persists results | |
| 87 | +| [`src/trigger/get-basic-info.ts`](https://github.com/triggerdotdev/examples/blob/main/smart-spreadsheet/src/trigger/get-basic-info.ts) | Extracts company website and description | |
| 88 | +| [`src/trigger/get-industry.ts`](https://github.com/triggerdotdev/examples/blob/main/smart-spreadsheet/src/trigger/get-industry.ts) | Classifies company industry | |
| 89 | +| [`src/trigger/get-employee-count.ts`](https://github.com/triggerdotdev/examples/blob/main/smart-spreadsheet/src/trigger/get-employee-count.ts) | Finds employee headcount | |
| 90 | +| [`src/trigger/get-funding-round.ts`](https://github.com/triggerdotdev/examples/blob/main/smart-spreadsheet/src/trigger/get-funding-round.ts) | Discovers latest funding information | |
| 91 | + |
| 92 | +<RealtimeLearnMore /> |
0 commit comments