Back to blog

Guides · May 6, 2026

How to schedule tasks in Tempo apps (the missing scheduler)

Tempo (the AI React IDE at tempo.new, formerly Tempo Labs, not the Atlassian, Grafana, or Temporal.io product) is great at shipping a deployed React app. It does not schedule anything. The schedule has to live somewhere, either inside Convex `crons.ts` or in an external service that pings your deployed URL. Here is the pattern that works for both Convex and Supabase backends, with one dashboard.
crontap.com / blog
Tempo (the AI React IDE at tempo.new, formerly Tempo Labs, YC S23, not the Atlassian, Grafana, or Temporal.io product) ships a deployed React app and a backend template (Convex or Supabase). It does not ship a scheduler. Here is the 5-minute pattern Tempo users run to fire a Convex HTTP Action or a Supabase Edge Function on any cadence, in any IANA timezone, without writing a single line of cron syntax.

Tempo (the AI React IDE at tempo.new, formerly Tempo Labs, YC S23) is great at building and shipping React apps. It does not schedule anything. You opened the IDE, prompted the agent to build a SaaS, picked a template (Vite + Clerk + Convex + Stripe, or Vite + Supabase), clicked Share, deployed to Vercel, and now you want it to send a daily summary email at 9am. There is no Schedule tab. The schedule has to live somewhere, either inside Convex crons.ts or in an external service that pings your deployed URL. Here is the pattern that works for both backends, with one dashboard.

Quick disambiguation before we go further. This post is about Tempo / Tempo Labs at tempo.new, the visual AI IDE for React. It is not about Atlassian Tempo (Jira time tracking), Grafana Tempo (distributed tracing), or Temporal.io (durable workflow orchestration). All four products live at similar names, all four show up in the same search results, none of them are interchangeable. If you landed here while looking for one of the others, sorry, this is the React IDE.

Tempo (formerly Tempo Labs) is a visual React IDE. It is not a scheduler.

Tempo's job is to scaffold a React app and a one-click deploy. The schedule lives downstream, in whatever backend the SaaS template wired up.

Where the public URL comes from

When you click Share, Tempo deploys to Vercel and gives you a temporary preview URL. Per the Deploy and Share docs, that share link expires after 24 hours unless you claim the deploy to your own Vercel account. Claim it once, and you get a permanent URL like https://your-app.vercel.app. Anything you can call over HTTPS on that domain (a Convex HTTP Action, a Supabase Edge Function, or a Next.js / Vite route on Vercel) is fair game for an external scheduler.

Where Tempo ends and the backend starts

The Tempo IDE writes the React frontend. The backend is whatever template you picked from the SaaS templates gallery. The two big ones are Vite + Clerk + Convex + Stripe and a Vite + Supabase variant. Convex gives you mutations, queries, and HTTP Actions. Supabase gives you Postgres, pg_cron, and Edge Functions. Tempo gives you neither; it gives you the React shell that talks to one of them.

Why Tempo does not ship a scheduler

Three structural reasons, none of them likely to change soon.

Tempo is a frontend IDE; the backend is whatever template you picked

The full Tempo docs index has pages on the IDE, the chat, components, deploys, sharing, and templates. There is no scheduler page, no jobs page, no queues page, no background tasks page. The product is opinionated about not owning the backend, and a scheduler is firmly a backend concern.

Convex has cron jobs, but that is a Convex feature, not a Tempo one

If you picked a Convex template, you already have a scheduler. The Convex cron jobs reference covers the syntax: a single convex/crons.ts file where you register intervals and cadences against your internal Convex functions. It is a real scheduler with a UI in the Convex dashboard. The catch is that it lives entirely inside Convex, with Convex's metering, and it cannot fire URLs outside Convex without you writing the HTTP call yourself.

Supabase has pg_cron and Edge Functions, but you configure them in Supabase

If you picked a Supabase template, you have two options, neither of them in the Tempo UI. Supabase Edge Functions can be invoked over HTTPS but Edge Functions themselves do not schedule. pg_cron schedules SQL inside the database, which can call an Edge Function via net.http_post, which works but requires writing SQL and managing pg_cron from the Supabase dashboard.

For the low-tech Tempo user, both paths are "leave the IDE and go configure something in another product's dashboard", which is exactly the friction that made you pick a vibe-coding tool in the first place.

The 60-second fix

The structural fix is to keep the backend Tempo wired up and put the clock in one place that points at any URL it has, regardless of whether that URL is a Convex HTTP Action, a Supabase Edge Function, or anything else.

Crontap (cron)  ->  HTTPS POST  ->  Your Tempo-deployed function URL  ->  the actual work

Step 1: pick the backend you actually have

Open the Tempo project. Look at the chat history or the file tree:

  • If you see a convex/ folder, you are on Convex. The scheduler target is an HTTP Action URL: https://<deployment>.convex.site/<route>.
  • If you see supabase/functions/ and a .env with SUPABASE_URL, you are on Supabase. The target is an Edge Function URL: https://<project-ref>.supabase.co/functions/v1/<name>.
  • If you have neither, prompt the Tempo chat to add one. Something like: "Add a Convex HTTP Action at /cron/daily-digest that emails me yesterday's signups, and require an Authorization: Bearer header against process.env.CRON_SECRET."

Step 2: lock the URL down with a shared secret

Whichever backend you picked, the function URL is publicly callable by default. Generate a long random secret:

openssl rand -base64 32

Put it in the backend's environment (Convex dashboard, Settings, Environment Variables, or Supabase dashboard, Edge Functions, Secrets). The function checks the header on every call and returns 401 if it does not match.

Step 3: create the schedule in Crontap

Head to Crontap and click New schedule.

  1. URL. Paste the function URL from Step 1.
  2. Method. POST.
  3. Headers. Add Authorization: Bearer <your CRON_SECRET>. Crontap stores the value encrypted.
  4. Cadence. Type plain English ("every 5 minutes", "every Monday at 9am", "daily at 03:00") or paste a cron expression. Crontap previews the next 5 fires inline so you can sanity-check.
  5. Timezone. Pick the IANA zone the schedule actually means (Europe/Berlin, America/Los_Angeles, Asia/Singapore). One zone per schedule, no DST math.
  6. Failure alerts. Turn on email or a webhook (Slack, Discord, Telegram) so 4xx and 5xx ping you the moment they happen.

Step 4: press "Perform test" and verify

Click Perform test. Crontap fires one real POST to the URL. If you see 200, you are done. If you see 401, the bearer is mismatched. If you see 5xx, the function failed and the alerting just proved itself. Convex and Supabase both surface the run in their respective logs, so you can debug the body from either dashboard.

Fix this in 60 seconds with Crontap. Free forever tier. Three schedules. No credit card. Schedule your first job.

When Convex crons.ts is enough on its own

External cron is a shape, not a religion. If you picked the Convex template, you already have a scheduler that knows how to invoke internal Convex functions without an HTTP round trip. Use it for:

  • Pure-Convex work. A nightly cleanup that reads, mutates, and writes Convex tables, and never calls anything outside Convex. crons.ts is one file edit, and Convex bills the work the same way it bills an interactive call.
  • A single schedule on a Convex-only stack. If your whole app is Convex and you only need one cron, the locality (everything in convex/) is worth it.
  • Sub-minute internal fan-out. Convex's scheduler can run intervals in seconds for internal work; external HTTP cron tops out at one minute.

For everything else (cross-environment parity, per-IANA timezone, alerting on failure into Slack or Discord, multiple cadences against the same backend, or any schedule that needs to fire a Supabase Edge Function or a Stripe sync that is not pure Convex), external cron pointing at a Convex HTTP Action wins on visibility and operational simplicity.

The same logic applies to Supabase. pg_cron is fine for SQL maintenance jobs that live inside the database. The moment a schedule needs to fire an Edge Function, send a Slack message on failure, or run on a per-tenant timezone, external cron is the smaller answer.

Real things teams schedule on Tempo apps

A few shapes that come up over and over in Tempo SaaS builds.

Daily summary email via Resend

The Tempo app sends a daily activity summary via Resend at 09:00 in the user's local timezone. The function reads the last 24 hours of events from Convex or Supabase, formats a digest, hands it to Resend. Crontap fires the function once per timezone, one schedule per IANA zone, no DST math.

Hourly Stripe sync via a Convex HTTP Action

A Convex HTTP Action pulls active Stripe subscriptions, reconciles against the Convex subscriptions table, and posts any drift to Slack. Crontap fires 0 * * * * every hour. No crons.ts edit, no redeploy when you want to bump the cadence to every 30 minutes.

Weekly cleanup of stale rows

Once a week, an Edge Function (or a Convex internal action) deletes soft-deleted rows older than 30 days, archives old logs, prunes orphaned uploads. Crontap fires 0 03 * * SUN Sunday at 3am in the project's home timezone.

Per-tenant nightly digest with timezone

The app has tenants in three timezones. One Crontap schedule per timezone, each at 0 21 * * * in Europe/London, America/New_York, and Asia/Tokyo. The function takes a tz query param and only emails users in that zone.

FAQ

Why does my Tempo deploy URL expire after 24 hours?

Per the Deploy and Share docs, the initial Share link is a temporary preview. Claim the deploy to your own Vercel account once and the URL becomes permanent. Crontap waits patiently while you claim it; once the URL is stable, point the schedule at the permanent domain and you are done.

Do I need to "claim" the deploy to my own Vercel account first?

For anything you actually want running on a schedule, yes. A 24-hour preview URL is fine for an internal demo, useless as a cron target. Claim the deploy, optionally add a custom domain, then create the Crontap schedule against the stable URL.

Does this work with Tempo's free plan?

Yes for the cron half. Crontap's free tier covers three schedules at hourly cadence, no credit card. Tempo's pricing covers the IDE itself; the schedule is independent of Tempo prompts. Whether your Convex or Supabase backend has its own free tier is the third question (both do, with reasonable allowances for small projects).

I picked the Vite + Clerk + Convex + Stripe template. Where is the schedule URL?

In the Convex dashboard, under HTTP Actions. Anything you defined with httpAction in convex/http.ts shows up there with a public URL of the shape https://<deployment>.convex.site/<route>. Copy that, paste into Crontap, you are done.

Move the clock out of crons.ts. Free forever tier. Three schedules. No credit card. Schedule your first job.

References

Related on Crontap

From the blog

Read the blog

Guides, patterns and product updates.

Tutorials on scheduling API calls, webhooks and automations, plus deep dives into cron syntax, timezones and reliability.

Alternatives

Vercel Cron every minute: beating the Hobby hourly limit

Vercel Cron caps Hobby at hourly cadence and 5 jobs, and ties every change to a redeploy. Here is the external cron pattern teams use to ship per-minute schedules, per-IANA timezones, and one dashboard across projects without paying $20/mo per user for Pro.

Alternatives

Cloud Run cron without Cloud Scheduler

Cloud Scheduler costs $0.10 per job per month after the first 3 and asks for OIDC plus IAM bindings on every target. Here is the IAM-free pattern Cloud Run teams use to fire their .run.app URLs on a clock with one bearer token and one dashboard across every GCP project.