Quick links
- Repo: ai-agent-vercel-examples/product-hunt-agent
- Express app guide: agent/README.md
- Agent definition: agent/lib/producthunt/agent.js
- Product Hunt services: agent/lib/producthunt/services.js
- Sample UI: web/index.html
What you’ll build
- A Vercel AI SDK
Experimental_Agentthat can:- Pull top Product Hunt posts (all-time or timeframe aware)
- Search posts via Product Hunt’s public Algolia index
- Offer practical launch guidance grounded in tool output
- Emit a
CONFETTIaction payload for your frontend
- An Express API exposing
/api/top*,/api/search,/api/chat, and a streaming/agentendpoint adapted for CometChat - A Product Hunt–inspired static page that mounts the CometChat widget and handles the confetti tool
Prerequisites
- Node.js 18 or newer
- Environment variables:
OPENAI_API_KEY(required for all chat routes)PRODUCTHUNT_API_TOKEN(GraphQL token; endpoints return empty arrays if omitted)- Optional:
OPENAI_MODEL(defaultsgpt-4o-mini),TEMPERATURE(defaults0.7),PORT(defaults3000)
- A CometChat app to host the agent/chat widget
How it works
agent/lib/producthunt/agent.jswires a Vercel AI SDKExperimental_Agentwith four tools:getTopProducts,getTopProductsByTimeframe,searchProducts, andtriggerConfetti.agent/lib/producthunt/services.jscalls Product Hunt’s GraphQL API (with optional token), parses natural-language timeframes, and queries Algolia for search.agent/routes/producthunt.jsexposes REST endpoints with JSON responses and permissive CORS for local development.agent/routes/agent.jsconverts CometChat payloads to Vercel AI SDK messages via@cometchat/vercel-adapter, streams Server-Sent Events (SSE), and merges any extra tools you forward.web/index.htmlmounts the CometChat Chat Embed, calls your API for leaderboard data, and executes the confetti action usingcanvas-confetti(with a fallback renderer when the CDN is unavailable).
Step 1 — Define Product Hunt tools
File:agent/lib/producthunt/agent.js
getTopProductsreturns top posts by votes (1–10 items, default 3).getTopProductsByTimeframeaccepts timeframes liketoday,yesterday,this-week,YYYY-MM-DD, or ranges (from:2024-08-01 to:2024-08-15), plus optional timezone and limit.searchProductswraps Product Hunt’s public Algolia index and clamps results (1–50).triggerConfettiemits a structured payload (colors, particleCount, spread, origin, etc.) that your UI can interpret as an action.- Helper utilities sanitize limits, build Markdown tables, and ensure empty results are handled gracefully.
Step 2 — Instantiate the agent
Also inagent/lib/producthunt/agent.js:
createProductHuntAgent()assertsOPENAI_API_KEYbefore constructing anExperimental_Agent.- System prompt (
buildSystemPrompt) reminds the model when to call each tool, to summarise results as Markdown tables, and to fire confetti when users celebrate. - Default model is
gpt-4o, but you can override by passing{ model: 'gpt-4o-mini' }or settingOPENAI_MODEL. - The agent returns both text and
toolResults, letting the REST API surface raw data alongside the response.
Step 3 — Expose REST & streaming endpoints
Files: Highlights:GET /api/healthconfirms the service.GET /api/top,/api/top-week, and/api/top-rangereturn leaderboard JSON based on votes, rolling windows, or natural-language timeframes.GET /api/search?q=...performs Algolia-backed lookup with clamped limits and helpful validation errors.POST /api/chataccepts{ message }or{ messages: [...] }and responds with{ reply, toolResults, usage }.POST /agentstreams SSE events that already match CometChat’s expectations (text_message,tool_call_start,tool_call_result, etc.), courtesy ofmapVercelStreamChunkToCometChatEvent.- Tool preferences such as timeframe, timezone, or limit can be supplied via
toolParamsin the SSE payload and are woven into the system prompt for that run.
Step 4 — Run locally
- Install deps:
- Create
.env(or export vars): - Start the server:
- Open
http://localhost:3000to view the default Jade page, or loadweb/index.htmlvia a static server pointingwindow.PH_AGENT_APItohttp://localhost:3000.
Step 5 — Handle frontend actions
File:web/index.html
- Mounts CometChat Chat Embed and logs a demo user.
- Provides helper functions to fetch
/api/top-rangeand render Product Hunt-style cards. - Implements
actions.triggerConfettithat lazily loadscanvas-confetti(with a fallback canvas animation) and respects the agent’s payload (colors, particle count, etc.). - Use this file as a reference when wiring confetti handlers into your own widget or UI Kit export.
Step 6 — API overview
GET /api/health→{ ok: true }GET /api/top?limit=3→ top posts by votesGET /api/top-week?limit=3&days=7→ rolling window rankingGET /api/top-range?timeframe=today&tz=America/New_York&limit=3→ timeframe ranking + metadataGET /api/search?q=notion&limit=10→ Algolia resultsPOST /api/chatwith{ "message": "What should I prep before launch?" }→{ reply, toolResults }POST /agent(SSE) → CometChat-compatible events for streaming responses and tool traces
Step 7 — Deploy
- Deploy the Express app (Node.js 18+) to your platform of choice (Vercel, Render, Fly.io, Railway, etc.).
- Set
OPENAI_API_KEY,PRODUCTHUNT_API_TOKEN,OPENAI_MODEL, andTEMPERATUREas environment variables. - Expose the streaming
/agentendpoint over HTTPS (required by CometChat) and keep CORS permissive or scoped to your domains. - Host the static Product Hunt UI (optional) on any CDN or static site host; point
window.PH_AGENT_APIto the deployed backend.
Step 8 — Connect in CometChat
- Dashboard → your App → AI Agents → Add Agent
- Provider: Vercel AI SDK
- Agent ID: match the ID you’ll reference in your UI (e.g.,
producthunt) - Deployment URL:
https://your-domain.tld/agent - Optional: add greetings, suggested prompts such as “Celebrate today’s top 3 Product Hunt launches,” and map frontend actions to the
triggerConfettihandler. - Save and toggle the agent to Enabled.
Step 9 — Test
- Hit
/api/healthto confirm the service. - Verify
/api/search?q=linear&limit=5returns data (Algolia key is bundled). - Call
/api/top-range?timeframe=todayto ensure the Product Hunt token works (expect empty arrays if the token is missing). - Use the curl stream above and confirm CometChat renders partial replies plus the confetti action.
- In UI Kit Builder or your widget, send “Throw confetti for our launch” and verify the handler fires.
Security & production checklist
- Keep
OPENAI_API_KEYandPRODUCTHUNT_API_TOKENserver-side only; never expose them in the browser or widget exports. - Add authentication (API key/JWT) and tighten CORS once deployed.
- Rate-limit
/agentand/api/top*endpoints; clamp user-provided limits to sane values (already partially enforced in code). - Log errors and tool usage without storing sensitive content; monitor for failed API calls so you can refresh credentials.
- For long-lived deployments, handle Product Hunt API quota/burst limits gracefully (retry with backoff, cache top results).
Troubleshooting
/api/top*returns empty arrays: ensurePRODUCTHUNT_API_TOKENis set and valid.- Algolia search empty: check outbound network access and confirm you didn’t hit rate limits.
- Chat replies lack tables: confirm tool calls succeed (inspect
toolResultsor server logs); the agent falls back to narrative answers if no posts are returned. - Confetti never fires: double-check the action name (
triggerConfetti) and that your handler loadscanvas-confettior provides a fallback. - SSE disconnects immediately: verify your reverse proxy supports streaming and that
Cache-Control: no-cacheheaders are preserved.