To use SurveyMonkey with V0 by Vercel, create a Next.js API route at app/api/surveymonkey/route.ts that proxies requests to the SurveyMonkey REST API using an OAuth2 access token. Store your access token as SURVEYMONKEY_ACCESS_TOKEN in Vercel environment variables. V0 generates your survey dashboard UI and your API route fetches surveys, responses, and analytics from SurveyMonkey server-side.
Building a Custom SurveyMonkey Dashboard with V0 by Vercel
V0 by Vercel generates polished Next.js UI components quickly, but many teams need more than SurveyMonkey's default dashboards — they want survey data embedded directly in their product, admin panel, or CRM. The SurveyMonkey REST API v3 exposes surveys, collectors, individual responses, and rollup analytics, making it possible to build exactly the dashboard your team needs.
The integration works through a Next.js API route that proxies all SurveyMonkey API calls server-side. SurveyMonkey uses OAuth2 for authentication, which means your access token must stay on the server — exposing it in client-side JavaScript would allow anyone to read your survey responses and account data. The API route receives requests from your V0-generated frontend components and forwards them to api.surveymonkey.com with the access token in the Authorization header.
SurveyMonkey's API is particularly useful for three scenarios: embedding survey response data into internal analytics dashboards, triggering surveys programmatically based on user actions (via webhooks and collectors), and building custom response visualization beyond SurveyMonkey's built-in charts. V0 generates the chart components, data tables, and filter controls while your API route handles the authentication and data fetching.
Integration method
V0 generates your survey dashboard or response visualization UI components. A Next.js API route proxies all SurveyMonkey REST API calls server-side, keeping your OAuth access token secure. The SurveyMonkey REST API v3 supports fetching surveys, collectors, responses, and aggregate answer data. Your frontend components fetch data from your API route, not directly from SurveyMonkey.
Prerequisites
- A V0 account at v0.dev — free tier is sufficient for UI generation
- A SurveyMonkey account — the API requires a paid plan (Advantage or higher) for full response access
- A SurveyMonkey Developer App with an OAuth access token — created at developer.surveymonkey.com
- A Vercel account (free) for deploying and configuring environment variables
- At least one survey with responses in your SurveyMonkey account to test with
Step-by-step guide
Get Your SurveyMonkey API Access Token
Get Your SurveyMonkey API Access Token
SurveyMonkey uses OAuth2 for API authentication. For integrations where you're accessing your own account's data (rather than multiple users' accounts), you can use a long-lived personal access token rather than implementing the full OAuth2 flow. To create a personal access token, first register a developer app at developer.surveymonkey.com. Log in with your SurveyMonkey credentials, click 'My Apps', then 'Add App'. Give your app a name (e.g., 'My Dashboard Integration'), set the OAuth Redirect URL to your Vercel deployment URL (you can use https://placeholder.vercel.app for now and update it later), and select the scopes your integration needs: surveys_read, responses_read, and users_read are sufficient for a read-only dashboard. After creating the app, go to the app's Settings and find the 'Access Token' section. Click 'Generate Access Token' — this creates a personal token tied to your SurveyMonkey account that grants the permissions you specified. Copy this token immediately; you'll store it as an environment variable in Vercel. For V0 app development, also note your survey IDs from the SurveyMonkey interface (Edit Survey → look at the URL, the number is the survey ID) — you'll need these to test your API route. The SurveyMonkey API base URL is https://api.surveymonkey.com/v3/ and all responses are paginated with a default page size of 50.
Pro tip: Personal access tokens don't expire by default but can be revoked from your SurveyMonkey developer app settings. Rotate the token if you accidentally expose it.
Expected result: A SurveyMonkey developer app is created and a personal access token is generated. The token string is copied and ready to store in Vercel as an environment variable.
Create the SurveyMonkey API Routes
Create the SurveyMonkey API Routes
Create Next.js API routes that proxy requests to the SurveyMonkey REST API. Because the SurveyMonkey access token grants full read access to your account's surveys and responses, it must never appear in client-side JavaScript. All SurveyMonkey API calls go through these server-side route handlers. Create separate route files for different SurveyMonkey endpoints to keep the code clean. The surveys list endpoint (/api/surveymonkey/surveys) fetches all your surveys with basic metadata. The responses endpoint (/api/surveymonkey/responses) fetches individual responses for a specific survey. The rollup endpoint (/api/surveymonkey/rollup) fetches aggregated answer statistics — perfect for building charts without processing raw data. Each route handler reads the SURVEYMONKEY_ACCESS_TOKEN environment variable and sets it as a Bearer token in the Authorization header. The SurveyMonkey API uses standard HTTP authentication: Authorization: Bearer YOUR_TOKEN_HERE. Add pagination support by forwarding the page and per_page query parameters to SurveyMonkey's API. Their API returns a meta object with total, count, per_page, and links fields for navigating paginated results. Forward these to your frontend so it can implement infinite scroll or page-based navigation. For the rollup endpoint specifically — which returns aggregated data per question — be aware that SurveyMonkey only returns rollup data for simple question types (rating scales, multiple choice, dropdown). Open-ended text questions return individual response text and require client-side aggregation if you want to display them in summary form.
Create a Next.js API route at app/api/surveymonkey/surveys/route.ts that fetches the list of surveys from the SurveyMonkey API at https://api.surveymonkey.com/v3/surveys. Accept optional query parameters for page and per_page. Use process.env.SURVEYMONKEY_ACCESS_TOKEN as the Bearer token in the Authorization header. Return the surveys array and pagination metadata as JSON.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';23const SM_API_BASE = 'https://api.surveymonkey.com/v3';45async function smFetch(path: string, token: string) {6 const response = await fetch(`${SM_API_BASE}${path}`, {7 headers: {8 Authorization: `Bearer ${token}`,9 'Content-Type': 'application/json',10 },11 next: { revalidate: 120 },12 });1314 if (!response.ok) {15 throw new Error(`SurveyMonkey API error: ${response.status} ${await response.text()}`);16 }1718 return response.json();19}2021// GET /api/surveymonkey/surveys22export async function GET(request: NextRequest) {23 const token = process.env.SURVEYMONKEY_ACCESS_TOKEN;2425 if (!token) {26 return NextResponse.json(27 { error: 'SurveyMonkey access token not configured' },28 { status: 500 }29 );30 }3132 const { searchParams } = new URL(request.url);33 const page = searchParams.get('page') || '1';34 const perPage = searchParams.get('per_page') || '20';3536 try {37 const data = await smFetch(38 `/surveys?page=${page}&per_page=${perPage}&include=response_count,date_modified`,39 token40 );41 return NextResponse.json(data);42 } catch (error) {43 const message = error instanceof Error ? error.message : 'Unknown error';44 return NextResponse.json({ error: message }, { status: 500 });45 }46}Pro tip: Include response_count and date_modified in the ?include= parameter of the surveys list endpoint — these fields are not returned by default but are essential for a useful dashboard.
Expected result: GET requests to /api/surveymonkey/surveys return a JSON array of surveys with response counts. The route appears in Vercel's Functions tab. SurveyMonkey API errors return descriptive error messages rather than raw status codes.
Create Responses and Rollup Endpoints
Create Responses and Rollup Endpoints
Build two additional API routes: one for fetching individual survey responses and one for fetching rollup (aggregated) statistics. These cover the most common dashboard needs — the responses route for detailed individual answer views and the rollup route for aggregate charts and summary cards. The responses endpoint at app/api/surveymonkey/responses/route.ts accepts a surveyId query parameter and returns a paginated list of responses. Each response from SurveyMonkey's /surveys/{id}/responses/bulk endpoint includes the respondent's IP, submission date, and an array of answer objects keyed by question ID. You'll need to request the full details with the /bulk endpoint rather than the /responses endpoint to get answer data. The rollup endpoint at app/api/surveymonkey/rollup/route.ts calls /surveys/{id}/rollups, which returns aggregated statistics per question — for multiple choice questions, it shows count and percentage per answer option; for rating scales, it shows average score and distribution. This endpoint powers pie charts, bar charts, and NPS score calculations without requiring you to process hundreds of individual responses. Both routes should validate that the surveyId parameter is present and is a numeric string before forwarding the request to SurveyMonkey. Missing or malformed IDs result in cryptic SurveyMonkey API errors — a frontend validation layer in the route prevents confusing error messages. V0 generates dashboard components that consume these endpoints, giving you a complete survey analytics system without building a separate backend.
Create a Next.js API route at app/api/surveymonkey/rollup/route.ts that accepts a surveyId query parameter and fetches aggregate answer statistics from the SurveyMonkey API at https://api.surveymonkey.com/v3/surveys/{surveyId}/rollups. Use process.env.SURVEYMONKEY_ACCESS_TOKEN as the Bearer token. Return the per_question rollup data as JSON. Return a 400 error if surveyId is missing.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';23const SM_API_BASE = 'https://api.surveymonkey.com/v3';45export async function GET(request: NextRequest) {6 const token = process.env.SURVEYMONKEY_ACCESS_TOKEN;78 if (!token) {9 return NextResponse.json(10 { error: 'SurveyMonkey access token not configured' },11 { status: 500 }12 );13 }1415 const { searchParams } = new URL(request.url);16 const surveyId = searchParams.get('surveyId');1718 if (!surveyId || !/^\d+$/.test(surveyId)) {19 return NextResponse.json(20 { error: 'Valid numeric surveyId query parameter is required' },21 { status: 400 }22 );23 }2425 try {26 // Fetch rollup (aggregate) data27 const [rollupRes, surveyRes] = await Promise.all([28 fetch(`${SM_API_BASE}/surveys/${surveyId}/rollups`, {29 headers: {30 Authorization: `Bearer ${token}`,31 'Content-Type': 'application/json',32 },33 next: { revalidate: 300 },34 }),35 fetch(`${SM_API_BASE}/surveys/${surveyId}/details`, {36 headers: {37 Authorization: `Bearer ${token}`,38 'Content-Type': 'application/json',39 },40 next: { revalidate: 300 },41 }),42 ]);4344 if (!rollupRes.ok) {45 return NextResponse.json(46 { error: `SurveyMonkey rollup error: ${rollupRes.status}` },47 { status: rollupRes.status }48 );49 }5051 const rollupData = await rollupRes.json();52 const surveyData = surveyRes.ok ? await surveyRes.json() : null;5354 return NextResponse.json({55 rollup: rollupData,56 survey: surveyData ? { title: surveyData.title, id: surveyData.id } : null,57 });58 } catch (error) {59 const message = error instanceof Error ? error.message : 'Unknown error';60 return NextResponse.json({ error: message }, { status: 500 });61 }62}Pro tip: Fetch the survey details and rollup data in parallel using Promise.all() — this cuts the response time roughly in half compared to sequential fetches, since both requests are independent.
Expected result: GET /api/surveymonkey/rollup?surveyId=12345678 returns aggregated answer statistics per question. The data includes answer counts and percentages per choice for multiple-choice questions. A missing surveyId returns a 400 with a descriptive error.
Set Environment Variables in Vercel and Generate the Dashboard UI
Set Environment Variables in Vercel and Generate the Dashboard UI
Store your SurveyMonkey access token in Vercel's environment variables so the API routes can authenticate with the SurveyMonkey API. The access token must not have a NEXT_PUBLIC_ prefix — it's a server-only secret that grants full read access to your SurveyMonkey account data. Push your V0 project to GitHub using V0's Git panel. Then in your Vercel project, go to Settings → Environment Variables. Click Add New and set key = SURVEYMONKEY_ACCESS_TOKEN, value = your personal access token from Step 1. Check all three environment scopes: Production, Preview, and Development. Click Save. Then go to Deployments and click Redeploy to apply the variable. For local development, create a .env.local file at your project root with the same variable and add it to .gitignore immediately. Now generate the dashboard UI in V0. Prompt V0 to create the survey dashboard components using the API routes you've built. Be specific: describe the exact data you want to display (response counts, answer percentages, score distributions) and the chart types you want (bar charts, donut charts, data tables). V0's AI understands Recharts and other charting libraries and can generate interactive visualizations. Once V0 creates the components, review the generated fetch calls to ensure they're calling your /api/surveymonkey/* routes rather than the SurveyMonkey API directly.
Create a survey dashboard page at app/dashboard/surveys/page.tsx. At the top, show a grid of survey cards fetched from GET /api/surveymonkey/surveys. Each card shows the survey title, total responses, and a 'View Analytics' button. Clicking the button navigates to /dashboard/surveys/[id] where a bar chart shows answer distributions from GET /api/surveymonkey/rollup?surveyId={id}. Use Recharts for the bar chart.
Paste this in V0 chat
1# .env.local — never commit this file to git2SURVEYMONKEY_ACCESS_TOKEN=your_personal_access_token_herePro tip: SurveyMonkey's API has rate limits of 120 requests per minute on paid plans. Add next: { revalidate: 300 } to fetch calls in your API routes to cache responses for 5 minutes and stay well within limits.
Expected result: SURVEYMONKEY_ACCESS_TOKEN is set in Vercel Dashboard. After redeployment, the API routes authenticate successfully. The V0-generated dashboard displays a list of surveys with response counts. Clicking a survey loads its rollup analytics with a bar chart.
Deploy to Vercel and Test the Full Integration
Deploy to Vercel and Test the Full Integration
With the API routes created and the access token configured, deploy your app to Vercel. If your V0 project is connected to GitHub, pushing triggers automatic deployment. Otherwise use the Vercel Dashboard → Deployments → Redeploy button or V0's built-in Publish flow. After deployment (typically 30–60 seconds), open the production URL and navigate to your survey dashboard. The page should load your SurveyMonkey surveys from the API route. Click into a survey to see the rollup analytics and response viewer. Verify the data matches what you see in the SurveyMonkey web interface. For debugging, test your API routes directly by opening your-app.vercel.app/api/surveymonkey/surveys in the browser — a successful response returns a JSON array of surveys. If you see a 500 error with 'SurveyMonkey access token not configured', the environment variable hasn't been applied yet (redeploy required). If you see a 401, the token is invalid — regenerate it in your SurveyMonkey developer app settings. Check the Vercel Dashboard → Functions tab to see your API routes listed and review invocation logs. The logs show the exact SurveyMonkey API error if the integration fails. For complex integrations — like building real-time response notification systems, embedding surveys directly in your app, or setting up SurveyMonkey webhooks that trigger server-side processing — RapidDev can help architect the solution for production scale.
Pro tip: If your SurveyMonkey account is on a free plan, the API returns 403 for response-level endpoints. Upgrade to at least Advantage tier, or test with the /surveys endpoint which works on all plans.
Expected result: The deployed dashboard shows surveys with response counts, analytics charts load for individual surveys, and the Vercel Functions tab confirms API routes are being invoked successfully.
Common use cases
Customer Satisfaction Dashboard
Build an internal NPS or CSAT dashboard that fetches survey responses from SurveyMonkey and displays response trends, score distributions, and individual comments in a visual dashboard. Your team accesses it directly in your app rather than switching to the SurveyMonkey interface.
Create a customer satisfaction dashboard page with three summary cards showing NPS score, total responses, and response rate. Below, add a bar chart showing NPS distribution (Detractors, Passives, Promoters) and a scrollable list of recent verbatim responses with respondent email, submission date, and score. Fetch all data from GET /api/surveymonkey/responses?surveyId=SURVEY_ID.
Copy this prompt to try it in V0
Event Feedback Collector
Display a summary of post-event survey feedback inline on an event management page. Show aggregate scores for each question and highlight top comments, so event organizers can review feedback without leaving your platform.
Build an 'Event Feedback' section for an event detail page. Show average rating per question as a star rating display, a donut chart for overall satisfaction, and a card grid of top written responses. Add a 'View All Responses' button that expands to show a paginated table. Data comes from GET /api/surveymonkey/rollup with the survey ID as a query parameter.
Copy this prompt to try it in V0
Product Research Response Viewer
Create a research repository page that lists all product research surveys with their response counts and completion rates. Clicking a survey opens an inline response viewer showing individual response details without leaving your app.
Create a 'Research Library' page with a list of survey cards, each showing survey title, creation date, number of responses, and completion rate percentage. Clicking a card expands to show a paginated table of individual responses with columns for respondent ID, submission date, and a 'View Full Response' button. Fetch the survey list from GET /api/surveymonkey/surveys and responses from GET /api/surveymonkey/responses?surveyId={id}.
Copy this prompt to try it in V0
Troubleshooting
API route returns 401 Unauthorized from SurveyMonkey
Cause: The access token is invalid, expired, or the SURVEYMONKEY_ACCESS_TOKEN environment variable is missing or was not applied by a redeployment.
Solution: Go to Vercel Dashboard → Settings → Environment Variables and verify SURVEYMONKEY_ACCESS_TOKEN is present. If it was added after the last deploy, go to Deployments and click Redeploy. If the token was revoked, generate a new one in SurveyMonkey → developer.surveymonkey.com → My Apps → your app → Access Token.
API returns 403 Forbidden when fetching responses or rollups
Cause: Your SurveyMonkey plan does not include API access to response data. SurveyMonkey restricts response-level API access to Advantage, Premier, and Enterprise plans.
Solution: Upgrade your SurveyMonkey plan to at least Advantage to access response data via the API. As a workaround on free plans, the /surveys endpoint works and provides basic survey metadata with response counts.
Rollup endpoint returns data for multiple-choice questions but not open-ended questions
Cause: SurveyMonkey's rollup API only aggregates structured answer types (rating scales, multiple choice, matrix). Open-ended text answers are returned as null in the rollup data and require fetching individual responses.
Solution: For open-ended questions, use the /surveys/{id}/responses/bulk endpoint to fetch individual responses and aggregate them client-side. Check the question type in the survey details response to conditionally show rollup data vs individual responses.
1// Check question type before showing rollup data2const hasRollupData = question.answers && question.answers.choices && question.answers.choices.length > 0;3// Show rollup chart for structured questions, response list for open-endedSurvey dashboard is slow to load — takes 3-5 seconds on first visit
Cause: The API routes are making multiple sequential SurveyMonkey API calls without caching. SurveyMonkey's API also has response times of 500ms–1.5s per request.
Solution: Add next: { revalidate: 300 } to your fetch calls inside the API routes to cache SurveyMonkey responses for 5 minutes. Use Promise.all() to parallelize independent API calls. For the surveys list page, consider ISR (revalidate every 5 minutes) instead of dynamic rendering.
1// Add revalidate to cache SurveyMonkey responses2const response = await fetch(`${SM_API_BASE}/surveys`, {3 headers: { Authorization: `Bearer ${token}` },4 next: { revalidate: 300 }, // cache for 5 minutes5});Best practices
- Never expose the SurveyMonkey access token client-side — store it as SURVEYMONKEY_ACCESS_TOKEN without the NEXT_PUBLIC_ prefix and use only in server-side API routes
- Add next: { revalidate: 300 } to SurveyMonkey fetch calls in your API routes to cache responses and stay within the 120 requests/minute rate limit
- Use Promise.all() to parallelize independent API calls (survey details + rollup data) and cut response times in half
- Validate the surveyId parameter in your API routes before forwarding to SurveyMonkey — a numeric format check prevents cryptic API errors
- Use separate SurveyMonkey developer apps for production and staging environments so you don't pollute production analytics with test data
- Handle the 403 case gracefully in your UI — show a clear message when a survey's data requires a higher SurveyMonkey plan tier rather than displaying a generic error
- Cache survey structure (questions and answer options) more aggressively than response data — surveys rarely change while responses accumulate continuously
- For high-traffic dashboards, consider storing SurveyMonkey responses in your own database via scheduled sync rather than fetching from the API on every request
Alternatives
Typeform is better for conversational, consumer-facing forms with high completion rates — choose SurveyMonkey for enterprise research and structured survey workflows with advanced branching logic.
Google Analytics tracks behavioral data passively — choose it alongside SurveyMonkey when you want to correlate survey responses with traffic and conversion data from the same users.
FullStory captures behavioral data through session recording rather than explicit survey responses — use it when you want to understand what users do rather than what they say.
Frequently asked questions
Does the SurveyMonkey API work with free accounts?
Basic SurveyMonkey API access (survey list, survey structure) works with free developer apps, but accessing response data and rollup analytics requires an Advantage, Premier, or Enterprise plan. The /surveys endpoint returns survey metadata on all plans, but /responses/bulk and /rollups return 403 Forbidden on free accounts. Check developer.surveymonkey.com for the current plan requirements.
Do I need to implement the full OAuth2 flow, or can I use a simple token?
For integrations where you're only accessing your own SurveyMonkey account data (not acting on behalf of other users), you can use a personal access token from your developer app settings — no OAuth2 flow needed. The full OAuth2 flow is only required if you're building a SaaS product where multiple different SurveyMonkey users authorize your app to access their accounts.
Can I embed SurveyMonkey surveys directly in my V0 app?
Yes. SurveyMonkey provides a web link for each survey that can be embedded in an iframe, or you can use SurveyMonkey's JavaScript embed code to render the survey inline. For the embed, add the script in a useEffect hook in a client component to avoid SSR issues. The API integration covered in this tutorial is for reading existing response data — creating surveys programmatically requires additional API endpoints.
How do I handle SurveyMonkey's API rate limits?
SurveyMonkey limits API calls to 120 requests per minute on paid plans. Add next: { revalidate: 300 } to fetch calls inside your API routes to cache responses for 5 minutes, dramatically reducing API call volume. For dashboards with many concurrent users, consider storing survey data in your own database via a scheduled sync job rather than fetching directly from SurveyMonkey on every page load.
Can I use SurveyMonkey webhooks with my V0 Next.js app?
Yes. Create a webhook in SurveyMonkey pointing to your deployed Vercel URL at /api/surveymonkey/webhook. Your webhook route handler processes the payload and can store new responses in a database, trigger notifications, or update other services. Note that webhooks require a publicly accessible URL — they don't work with the V0 preview sandbox or localhost without a tunneling tool like ngrok.
Why does the rollup endpoint return null for some questions?
SurveyMonkey's rollup API only aggregates structured answer types: multiple choice, dropdown, matrix, and rating scales. Open-ended text questions return null in the rollup because there's no meaningful statistical aggregate of free-form text. For open-ended questions, fetch individual responses from the /responses/bulk endpoint and display them as a list of verbatim comments.
Is it possible to create or update surveys via the API?
Yes — the SurveyMonkey API supports POST requests to /surveys to create new surveys and PATCH to update existing ones. This requires the surveys_write scope in your developer app configuration. However, programmatic survey creation is complex since you need to specify question types, answer options, and page structure in the request body. For most V0 apps, reading and displaying existing surveys (created in the SurveyMonkey interface) is sufficient.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation