Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate RescueTime with V0

To integrate RescueTime with V0 by Vercel, generate a productivity dashboard UI with V0, create a Next.js API route that fetches your time-tracking and productivity data from the RescueTime Analytics API using your API key, add the key to Vercel environment variables, and deploy. Your dashboard will display time spent by category, daily productivity scores, and top-used applications.

What you'll learn

  • How to generate a productivity analytics dashboard UI with V0 and wire it to real RescueTime data
  • How to create a Next.js API route that authenticates with the RescueTime Analytics API
  • How to fetch daily productivity summaries, activity breakdowns, and efficiency scores
  • How to safely store and use your RescueTime API key in Vercel environment variables
  • How to render time-tracking charts and category summaries in a V0-generated Next.js app
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read30 minutesProductivityMarch 2026RapidDev Engineering Team
TL;DR

To integrate RescueTime with V0 by Vercel, generate a productivity dashboard UI with V0, create a Next.js API route that fetches your time-tracking and productivity data from the RescueTime Analytics API using your API key, add the key to Vercel environment variables, and deploy. Your dashboard will display time spent by category, daily productivity scores, and top-used applications.

Build a Personal Productivity Dashboard with RescueTime and V0

RescueTime quietly runs in the background on your computer, tracking every app and website you use and assigning productivity scores based on categories you configure. Its Analytics API makes all that data accessible — daily productivity scores, time spent per category (software development, communication, social media), top applications by time, and focus-time totals. V0 can generate the dashboard UI in minutes; the integration challenge is connecting that UI to real data through a secure server-side API route.

The RescueTime Analytics API uses simple key-based authentication — you append your API key to each request as a query parameter. Because this key grants read access to your time-tracking history, it belongs in a server-side environment variable, proxied through a Next.js API route rather than called directly from browser JavaScript. The API returns JSON data you can map to charts, progress bars, and summary stats in your dashboard.

This integration is particularly useful for SaaS founders who want to track their own productivity while building, coaches who want to analyze client productivity data (with appropriate authorization), or teams building internal tools that aggregate productivity metrics. The V0-generated UI provides a polished starting point — bar charts for daily time breakdowns, a productivity score gauge, and category summaries — that you can customize for your specific reporting needs.

Integration method

Next.js API Route

RescueTime integrates with V0-generated Next.js apps through a server-side API route that proxies requests to the RescueTime Analytics API. Your RescueTime API key is stored as a server-only environment variable in Vercel and never exposed to the browser. The React components V0 generates fetch data from your internal API route and render charts and summary cards showing productivity analytics.

Prerequisites

  • A RescueTime account with the desktop app installed and running (rescuetime.com) — the API only returns data after the app has tracked activity
  • Your RescueTime API key — found at rescuetime.com/anapi/manage under 'Create a new API Key'
  • A V0 account at v0.dev to generate the dashboard UI
  • A Vercel account to deploy the Next.js app and store environment variables securely
  • At least a few days of RescueTime tracking history so the API returns meaningful data for testing

Step-by-step guide

1

Generate the Productivity Dashboard UI with V0

Open V0 at v0.dev and prompt it to generate a productivity analytics dashboard. Be specific about the data visualizations you want — productivity score gauges, category breakdown charts, and activity lists map well to V0's component generation capabilities. V0 will create a Next.js App Router project with React components using shadcn/ui charts (built on Recharts) and Tailwind CSS. The generated components will include placeholder data arrays and likely mock fetch calls to endpoints like /api/rescuetime/summary. Review the preview — you should see a styled dashboard with sample charts and cards. The key components to note are how the charts expect their data formatted (usually arrays of objects with name and value keys) since you'll need to transform RescueTime's API response to match. Use V0's Git panel to push the project to a new GitHub repository. If V0 generates a client component that fetches data directly on mount via useEffect, that's fine for now — the API route you create will proxy the secure RescueTime call so the component's fetch call doesn't need your API key.

V0 Prompt

Build a productivity analytics dashboard with a productivity score card showing a large percentage number and color indicator (green for 70+, yellow for 40-69, red below 40), a donut chart breaking down time by category (Software Development, Communication, Utilities, Social Media, Other), a ranked list of today's top 5 apps by time spent, and total hours tracked today. Include a simple date picker. Data loads from /api/rescuetime/summary. Use a clean professional design.

Paste this in V0 chat

Pro tip: Ask V0 to add skeleton loading states to your dashboard components: 'Add skeleton loaders while data is being fetched from the API.' RescueTime API calls can take 1-2 seconds, and skeleton loaders prevent layout shifts.

Expected result: A styled productivity dashboard renders in V0's preview with sample chart data, a productivity score display, category breakdown, and app usage list — all ready to be connected to real RescueTime data.

2

Create the RescueTime API Route

Create an API route that acts as a secure proxy between your React components and the RescueTime Analytics API. The RescueTime API's main data endpoint is https://www.rescuetime.com/anapi/data — it accepts query parameters including key (your API key), perspective (interval or rank), resolution_time (day, week, month), restrict_begin and restrict_end (date range), and format (json). The response includes a 'rows' array where each row is [date, time_spent_seconds, number_of_people, activity_name, category, productivity_score]. Your API route reads the API key from process.env.RESCUETIME_API_KEY, constructs the query URL with appropriate parameters from the request's query string, fetches from RescueTime, and transforms the response into a clean JSON structure for your React components. Keep the transformation logic in the API route rather than the component — this makes it easier to adjust the data shape if RescueTime updates their API response format. The route should support query parameters like date and resolution so your UI's date picker can request different time ranges.

app/api/rescuetime/summary/route.ts
1// app/api/rescuetime/summary/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const RESCUETIME_API_BASE = 'https://www.rescuetime.com/anapi/data';
5
6interface RescueTimeRow {
7 date: string;
8 timeSpentSeconds: number;
9 activity: string;
10 category: string;
11 productivityScore: number;
12}
13
14export async function GET(request: NextRequest) {
15 const apiKey = process.env.RESCUETIME_API_KEY;
16
17 if (!apiKey) {
18 return NextResponse.json(
19 { error: 'RescueTime API key not configured' },
20 { status: 500 }
21 );
22 }
23
24 const { searchParams } = new URL(request.url);
25 const date = searchParams.get('date') || new Date().toISOString().split('T')[0];
26
27 const params = new URLSearchParams({
28 key: apiKey,
29 perspective: 'rank',
30 resolution_time: 'day',
31 restrict_begin: date,
32 restrict_end: date,
33 format: 'json',
34 });
35
36 try {
37 const response = await fetch(`${RESCUETIME_API_BASE}?${params.toString()}`, {
38 next: { revalidate: 300 }, // Cache for 5 minutes
39 });
40
41 if (!response.ok) {
42 throw new Error(`RescueTime API error: ${response.status}`);
43 }
44
45 const data = await response.json();
46
47 // Transform rows: [date, seconds, people, activity, category, productivity]
48 const rows: RescueTimeRow[] = (data.rows || []).map((row: (string | number)[]) => ({
49 date: row[0] as string,
50 timeSpentSeconds: row[1] as number,
51 activity: row[3] as string,
52 category: row[4] as string,
53 productivityScore: row[5] as number,
54 }));
55
56 // Compute summary stats
57 const totalSeconds = rows.reduce((sum, r) => sum + r.timeSpentSeconds, 0);
58 const productiveSeconds = rows
59 .filter((r) => r.productivityScore > 0)
60 .reduce((sum, r) => sum + r.timeSpentSeconds, 0);
61 const productivityPercent =
62 totalSeconds > 0 ? Math.round((productiveSeconds / totalSeconds) * 100) : 0;
63
64 // Group by category
65 const byCategory: Record<string, number> = {};
66 for (const row of rows) {
67 byCategory[row.category] = (byCategory[row.category] || 0) + row.timeSpentSeconds;
68 }
69 const categories = Object.entries(byCategory)
70 .map(([name, seconds]) => ({ name, hours: Math.round((seconds / 3600) * 10) / 10 }))
71 .sort((a, b) => b.hours - a.hours);
72
73 return NextResponse.json({
74 date,
75 totalHours: Math.round((totalSeconds / 3600) * 10) / 10,
76 productivityPercent,
77 topActivities: rows.slice(0, 10),
78 categories,
79 });
80 } catch (error) {
81 console.error('RescueTime API error:', error);
82 return NextResponse.json(
83 { error: 'Failed to fetch RescueTime data' },
84 { status: 500 }
85 );
86 }
87}

Pro tip: The next: { revalidate: 300 } option caches the RescueTime API response for 5 minutes on Vercel's edge. RescueTime's data is updated every few minutes anyway, so 5-minute caching avoids unnecessary API calls without showing stale data.

Expected result: Calling GET /api/rescuetime/summary returns a JSON object with totalHours, productivityPercent, categories array, and topActivities — ready for your dashboard components to consume.

3

Connect the Dashboard Components to the API Route

Now update your V0-generated React components to fetch from the API route instead of using mock data. If V0 generated a Server Component (no 'use client' directive), you can fetch directly in the component function using the standard fetch API. If it generated a Client Component with useEffect, you'll keep that pattern and just update the fetch URL. The transformation you did in the API route means your components receive clean data objects matching the chart library's expected format. For the donut chart showing category breakdown, map the categories array to the format your chart component expects — typically [{name: 'Software Development', value: 2.4}, ...]. For the productivity score display, use productivityPercent as a 0-100 number. For the activity list, use topActivities and convert timeSpentSeconds to a human-readable format (convert to minutes or hours using simple math). If V0 generated components using Recharts directly (via shadcn/ui's chart primitives), the data format should slot in naturally. Test by visiting your page locally or in V0's preview — you should see real data from your RescueTime account replacing the mock values. Add error handling to show a friendly message if the API route returns an error (for example, if RescueTime hasn't tracked anything today).

V0 Prompt

Update the productivity dashboard to fetch data from /api/rescuetime/summary?date={today's date in YYYY-MM-DD format} when the component mounts. Display the returned totalHours, productivityPercent as the score, categories array in the donut chart, and topActivities as a ranked list. Show a skeleton loader while fetching and an error message if the request fails. Add a date input that re-fetches data for the selected date.

Paste this in V0 chat

app/components/ProductivityDashboard.tsx
1// app/components/ProductivityDashboard.tsx
2'use client';
3
4import { useEffect, useState } from 'react';
5
6interface SummaryData {
7 date: string;
8 totalHours: number;
9 productivityPercent: number;
10 categories: { name: string; hours: number }[];
11 topActivities: { activity: string; timeSpentSeconds: number; productivityScore: number }[];
12}
13
14export default function ProductivityDashboard() {
15 const [data, setData] = useState<SummaryData | null>(null);
16 const [loading, setLoading] = useState(true);
17 const [error, setError] = useState<string | null>(null);
18 const [date, setDate] = useState(new Date().toISOString().split('T')[0]);
19
20 useEffect(() => {
21 setLoading(true);
22 fetch(`/api/rescuetime/summary?date=${date}`)
23 .then((res) => res.json())
24 .then((d) => {
25 setData(d);
26 setLoading(false);
27 })
28 .catch(() => {
29 setError('Failed to load RescueTime data');
30 setLoading(false);
31 });
32 }, [date]);
33
34 if (loading) return <div className="animate-pulse h-64 bg-gray-100 rounded-lg" />;
35 if (error) return <div className="text-red-500 p-4">{error}</div>;
36 if (!data) return null;
37
38 return (
39 <div className="space-y-6 p-6">
40 <div className="flex items-center justify-between">
41 <h1 className="text-2xl font-bold">Productivity Dashboard</h1>
42 <input
43 type="date"
44 value={date}
45 onChange={(e) => setDate(e.target.value)}
46 className="border rounded px-3 py-1 text-sm"
47 />
48 </div>
49 <div className="grid grid-cols-2 gap-4">
50 <div className="bg-white border rounded-lg p-4">
51 <div className="text-sm text-gray-500">Productivity Score</div>
52 <div className={`text-4xl font-bold ${
53 data.productivityPercent >= 70 ? 'text-green-600' :
54 data.productivityPercent >= 40 ? 'text-yellow-500' : 'text-red-500'
55 }`}>{data.productivityPercent}%</div>
56 </div>
57 <div className="bg-white border rounded-lg p-4">
58 <div className="text-sm text-gray-500">Total Hours Tracked</div>
59 <div className="text-4xl font-bold text-gray-800">{data.totalHours}h</div>
60 </div>
61 </div>
62 <div className="bg-white border rounded-lg p-4">
63 <h2 className="font-semibold mb-3">Time by Category</h2>
64 {data.categories.map((cat) => (
65 <div key={cat.name} className="flex justify-between py-1 text-sm">
66 <span>{cat.name}</span>
67 <span className="font-medium">{cat.hours}h</span>
68 </div>
69 ))}
70 </div>
71 </div>
72 );
73}

Pro tip: Format seconds to human-readable time in a utility function: const formatTime = (s: number) => s >= 3600 ? `${Math.floor(s/3600)}h ${Math.floor((s%3600)/60)}m` : `${Math.floor(s/60)}m`. Use this in your activity list for clarity.

Expected result: The dashboard component fetches real data from the API route and renders your actual RescueTime productivity score, category breakdown, and top activities for the selected date.

4

Add Environment Variable and Deploy to Vercel

Push your updated project to GitHub, then configure the RescueTime API key in Vercel. Open your Vercel Dashboard, navigate to your project, click Settings, then Environment Variables. Add a new variable named RESCUETIME_API_KEY and paste your API key (found at rescuetime.com/anapi/manage under the 'API Key' section — if you haven't created one, click 'Create a new API Key' and name it for your V0 app). This variable should NOT have the NEXT_PUBLIC_ prefix since it's a server-side secret used only in your API route. Set it for Production, Preview, and Development environments. Click Save. Trigger a new deployment from the Deployments tab or push a commit to your GitHub repository. Once deployed, open your Vercel URL and navigate to the dashboard page. Because RescueTime's API returns your personal time-tracking data, you should see real stats immediately if the desktop app has been running. If the dashboard shows an error or empty state, check the Vercel Function Logs (Vercel Dashboard → Deployments → click your deployment → Functions tab) to see the raw error from the RescueTime API. Common issues are an invalid API key or no data for the current date (RescueTime only tracks when the desktop app is running).

Pro tip: RescueTime's API rate limit is generous for personal use, but if you're polling frequently, the next: { revalidate: 300 } cache setting in your API route prevents redundant requests. For multi-user apps, each user would need their own API key which requires a different auth approach.

Expected result: Your Vercel deployment runs successfully, the RESCUETIME_API_KEY is injected into the API route at runtime, and your productivity dashboard loads real data from your RescueTime account when accessed via the Vercel URL.

Common use cases

Personal Productivity Dashboard

A personal analytics page that fetches the day's RescueTime data and displays total productive hours, a productivity score (0-100), and a breakdown of time by category. The user can filter by date range to compare productivity across weeks.

V0 Prompt

Create a productivity dashboard with a large productivity score gauge showing 0-100, a daily summary showing total productive hours vs unproductive hours, a bar chart of time spent by category (Software Development, Communication, Design, etc.), and a date range picker to filter the data fetched from /api/rescuetime/summary. Use a clean minimal design with green for productive time and gray for neutral.

Copy this prompt to try it in V0

Weekly Productivity Report Page

A report page that pulls the past 7 days of RescueTime data and shows trend lines, day-by-day productivity comparisons, and which applications consumed the most time that week. Useful for weekly retrospectives and habit improvement.

V0 Prompt

Build a weekly productivity report page showing a line chart of daily productivity scores over 7 days, a ranked list of top applications by total time spent, a comparison of this week vs last week productivity percentage, and a 'most focused day' highlight card. Data comes from /api/rescuetime/weekly.

Copy this prompt to try it in V0

Focus Time Tracker Widget

A widget that calls the RescueTime API to show today's total focus time (time spent in 'very productive' activities) versus the user's daily goal. A simple progress bar and current streak counter motivate consistent deep work habits.

V0 Prompt

Design a focus time widget with a circular progress bar showing today's focus hours out of a 4-hour goal, a 7-day streak indicator, and a small table of today's top focus activities. Fetch current data from /api/rescuetime/focus. Use an indigo and white color scheme.

Copy this prompt to try it in V0

Troubleshooting

API route returns empty rows array even though RescueTime shows data in the dashboard

Cause: The date range in the API request doesn't match when data was recorded, or the restrict_begin and restrict_end parameters are formatted incorrectly. RescueTime expects dates in YYYY-MM-DD format and uses the timezone configured in your account.

Solution: Verify the date format is YYYY-MM-DD (e.g., 2026-03-31). Check that your RescueTime account timezone matches the dates you're querying — data recorded at 11 PM in one timezone may appear under the next day in another. Log the full API URL in your route handler to debug the exact parameters being sent.

typescript
1// Log the full request URL for debugging
2console.log('Fetching:', `${RESCUETIME_API_BASE}?${params.toString()}`);

RescueTime API returns 401 Unauthorized

Cause: The API key is incorrect, expired, or was set in an environment variable with extra whitespace or quotes around it. Vercel environment variable values are used exactly as entered — any surrounding quotes or newlines become part of the value.

Solution: Go to rescuetime.com/anapi/manage to verify your API key is active. In Vercel Dashboard → Environment Variables, delete and re-add the RESCUETIME_API_KEY value, being careful not to include quotes or trailing spaces. Redeploy after making changes.

Dashboard shows 0 hours and 0% productivity for today

Cause: The RescueTime desktop app is not running on your computer, so no activity has been tracked. The API returns an empty rows array when there's no data for the requested period, causing all totals to default to zero.

Solution: Ensure the RescueTime app is installed, running, and not paused. Check the RescueTime web dashboard at rescuetime.com to confirm data is being recorded. Test the API with a past date that you know had activity to verify the API route is working correctly.

RESCUETIME_API_KEY is undefined in Vercel Functions logs

Cause: The environment variable was added to Vercel after the last deployment and the deployment hasn't been rebuilt with the new variable. Vercel injects environment variables at build time for the serverless function bundle.

Solution: After adding or changing environment variables in Vercel Dashboard, trigger a new deployment. Go to Deployments tab → click the three-dot menu on the latest deployment → Redeploy. The new deployment will include the updated environment variables.

Best practices

  • Never expose your RescueTime API key in client-side code or NEXT_PUBLIC_ environment variables — always proxy through an API route
  • Cache RescueTime API responses for 5-10 minutes using Next.js fetch caching (next: { revalidate: 300 }) since the data updates infrequently
  • Handle the case where no data exists for a date (empty rows array) gracefully with a friendly empty state rather than an error
  • Use the restrict_kind parameter to filter data by 'activity', 'category', or 'overview' depending on what granularity your dashboard needs
  • For team dashboards, require each user to provide their own RescueTime API key via your app's settings — never use a single shared key for multiple users
  • Display time in human-readable format (2h 15m) rather than raw seconds — this requires a simple utility function but dramatically improves dashboard readability
  • Add a refresh button that clears the Next.js cache and re-fetches fresh data for users who want up-to-the-minute accuracy

Alternatives

Frequently asked questions

Does the RescueTime API require OAuth or is an API key enough?

For accessing your own account data, an API key is sufficient. You generate the key at rescuetime.com/anapi/manage and include it as a query parameter in API requests. OAuth is only required if you're building an application that accesses other users' RescueTime data — for a personal productivity dashboard, the API key approach is simpler and recommended.

Can I display RescueTime data for multiple team members?

RescueTime's API key grants access only to the account that generated it. To show multiple team members' data, each person would need to provide their own API key through your app's settings. RescueTime does offer team plans with separate analytics per user, but each user's key accesses only their own data — there's no admin-level key that returns all users' data.

How often does RescueTime update its API data?

RescueTime syncs data from the desktop app approximately every 5-15 minutes. The API reflects data as of the last sync. This means very recent activity (last few minutes) may not appear yet. Setting a 5-minute cache in your API route (next: { revalidate: 300 }) aligns well with this update frequency.

What is the RescueTime API rate limit?

RescueTime doesn't publish a specific rate limit, but their API is designed for reasonable personal use — dozens of requests per hour. Aggressive polling (every few seconds) would likely trigger throttling. Using server-side response caching in your API route and only re-fetching on user action or at reasonable intervals (every 5-10 minutes) keeps you well within limits.

Can I access historical RescueTime data going back years?

Yes. The RescueTime API supports any date range through the restrict_begin and restrict_end parameters. You can fetch data going back to when you first installed the desktop app. For long date ranges (months or years), the API returns aggregated data rather than minute-by-minute logs, which is appropriate for trend charts.

Will this integration work on Vercel's free Hobby plan?

Yes. The RescueTime integration uses a simple GET API route with no special infrastructure requirements. Vercel Hobby's 300-second function timeout and 2GB memory are far more than sufficient for fetching and transforming RescueTime's API response. The only limitation is that Hobby functions have a 10-second default timeout for API routes, which is plenty for a single RescueTime API call.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.