Back to blog

Guides · Jan 2, 2026

How to schedule a Bubble.io workflow every minute (without burning workload units)

Bubble's native scheduler stops at daily and the only sub-daily path is a recursive API workflow that pays 0.7 WU per re-schedule. Here is the click-by-click walkthrough for exposing a public API workflow and firing it from external cron in 5 minutes, so the schedule itself costs 0 WU and your minute-cadence job stops eating your plan.
crontap.com / blog
Bubble's native Recurring event only supports Daily, Weekly, Monthly, Quarterly, Yearly. The only sub-daily path is a recursive API workflow that costs 0.7 WU per re-schedule (30,240 WU/month at minute cadence). Here is the click-by-click walkthrough for exposing a public API workflow and firing it from external cron, so the schedule itself costs 0 WU and your minute-cadence job stops eating your plan.

You wanted to send a payment-failed reminder 10 minutes after a Stripe webhook fires. Or poll a third-party API every minute for 500 users. Or run a 5am Tuesday digest in Europe/Berlin without your Bubble app being awake at 04:59. You opened the Bubble backend workflow editor, found Recurring event, clicked the Schedule dropdown, and saw five options: Daily, Weekly, Monthly, Quarterly, Yearly. That is not a bug. That is the entire native scheduler. Here is what teams on Starter and Growth plans actually do, and the workload-unit math that makes it the cheap path.

The cost-math sibling lives at Bubble Scheduled Workflows vs external cron. This post is the click-by-click how-to.

Why Bubble has no native every-minute scheduler

Bubble has two native paths to recurring work, and neither goes below daily cleanly.

Recurring event only supports Daily, Weekly, Monthly, Quarterly, Yearly

The Recurring event docs describe a single API: pick one of five cadences, pick a start datetime, point at a backend workflow. The dropdown is the dropdown. No "every 5 minutes", no "every hour", no custom cron expression. If your job needs to run more than once a day, Recurring event is not the tool.

Plan limits on recurring events per data thing

Even within those five cadences, Bubble caps Recurring event instances per data thing per app: Starter 1, Growth 5, Team 20. If your shape is "every user has their own weekly digest", you hit the cap fast on Starter, slower on Growth, eventually on Team.

Recursive API workflows are the only native sub-daily option

The native trick for anything sub-daily is a backend workflow that ends with Schedule API Workflow [self] at: Current date/time + N seconds. Bubble's docs on Recursive API workflows cover the pattern, with the warning that it is the more expensive option compared to alternatives. The why is structural: every iteration runs the work, then re-queues itself, and the re-queue itself is a billable workflow action.

The workload-unit cost of scheduling every minute on Bubble

Here is what makes the recursive shape costly.

0.7 WU per Schedule API Workflow call

Per Bubble's Scheduling API workflows docs, Schedule API Workflow is itself a workflow action, billed at 0.7 WU per call. That is the action the recursive loop fires at the end of every iteration to queue the next one.

0.6 WU per backend workflow action

Backend workflow actions average 0.6 WU each. A reasonable workflow body (one DB read, one HTTP call, one DB write) is around 1.8 WU. So one iteration of a minute-level recursive is roughly 0.7 + 1.8 = 2.5 WU.

The math: 30,240 WU per month on bookkeeping alone

A minute-cadence loop fires 60 times per hour, 1,440 per day, 43,200 per 30-day month. Multiply by the 0.7 WU per re-schedule: 43,200 × 0.7 = 30,240 WU per month on scheduling overhead, before any real work runs.

At Starter (175,000 WU/month), one loop eats ~17% of the plan

That is bookkeeping, not work. One minute-level recursive workflow at ~17% of a Starter plan's monthly allowance, and you have not done anything yet.

At Growth ~12%, at Team ~6%

Same overhead, larger plans: Growth (250,000 WU/month) ~12%, Team (500,000 WU/month) ~6%. Overage billing is $0.30 per 1,000 WU and uncapped, so a runaway loop you forgot to cancel can bill thousands of dollars before you notice.

The July 2024 default 10-iteration cap on new apps

Since July 2024 Bubble defaults the recursion cap on new apps to 10 iterations. A minute-cadence recursive that hits the cap stops silently after 10 minutes; you find out the next morning when Bubble emails you.

The fix: expose a public API workflow and call it from external cron

The structural fix is to take scheduling out of Bubble and put it somewhere that doesn't bill you per re-schedule.

Why external cron is 0 WU for scheduling

Bubble bills you for work it does, not for HTTP requests it receives. An inbound POST to your API workflow URL is not a billable action; it is just a request. The meter starts when the workflow body runs, not when the ping arrives. The 0.7 WU per re-schedule vanishes.

The endpoint shape

Public API workflows expose two URL prefixes by default:

  • https://{your-app}.bubbleapps.io/version-live/api/1.1/wf/{workflow} for production.
  • https://{your-app}.bubbleapps.io/version-test/api/1.1/wf/{workflow} for the development version.

Custom domains follow the same path: https://your-domain.com/version-live/api/1.1/wf/{workflow}.

Authentication options

Three reasonable shapes:

  1. Privacy rules. Mark the API workflow as authenticated, generate an API token in Settings, API, and have Crontap send Authorization: Bearer {token}.
  2. Shared-secret parameter. Add a secret text parameter and a top-level Only when current parameter's secret is X guard. Crontap sends the secret in the body or query string. The secret travels in cleartext over HTTPS, so rotate it occasionally.
  3. "Run without authentication". Fine for dev, dangerous in production. Don't do this with money attached.

We use option 2 in the walkthrough because it is the shortest click path. Switch to option 1 once you've confirmed the cron fires reliably for anything with money attached.

Step-by-step setup (5 minutes)

You need a Bubble app on any paid plan (Starter and up; the API workflow feature is gated on paid) and a Crontap account. Free tier available, with hourly cadence; minute cadence on Pro at $3.25/mo billed annually.

Step 1: Settings, API, enable backend workflows and the Workflow API

In the Bubble editor, open Settings, click the API tab, and tick:

  • This app exposes a Workflow API. Enables the /api/1.1/wf/... URL shape.
  • Enable Workflow API and backend workflows. Lets you write backend workflows at all.

If your app was created before backend workflows existed, this is the first time you'll see the Backend workflows entry in the page dropdown.

Step 2: Add a new backend workflow with the right ticks

Go to the page dropdown (top-left), pick Backend workflows, click New API workflow.

In the dialog, tick:

  • Expose as a public API workflow. Without this, the workflow is private and only callable from inside the app.
  • This workflow can be run without authentication (only if you are using the shared-secret approach below).

Name it something explicit like cron-poll-stripe so you can find it in logs.

Step 3: Add a secret parameter and a top-level guard

In the workflow's parameter list, click Add parameter, set Key name to secret, Type to text. Then in the workflow event editor, set a step Only when condition: Current parameter's secret is "your-shared-secret-string". Anything that doesn't match falls through and the workflow returns 200 with no work done.

Generate a strong secret locally:

openssl rand -base64 32

Paste it into the guard. Save.

Step 4: Copy the version-live endpoint URL

Open the API tab in Bubble. The workflow you just created shows up with two URLs (one for version-test, one for version-live). Copy the live URL. It looks like:

https://your-app.bubbleapps.io/version-live/api/1.1/wf/cron-poll-stripe

Step 5: Create a schedule in Crontap pointed at the URL

Head to Crontap and click New schedule.

  1. URL. Paste the live URL from Step 4.
  2. Method. POST.
  3. Body or query string. Add secret=your-shared-secret-string either in the body (form-encoded) or as a query param on the URL.
  4. Headers. Optional. If you went with privacy-rule auth in Step 3, add Authorization: Bearer {your-bubble-api-token} here instead.

Step 6: Pick the cadence

Type plain English ("every minute", "every 5 minutes", "every Tuesday at 5am") or paste a cron expression. Crontap previews the next 5 fires inline so you can sanity-check before saving. Minute cadence is the floor on Crontap Pro.

Step 7: Pick the IANA timezone

Bubble's app timezone is global. Crontap is per-schedule. If you want one job in Europe/Berlin and another in America/Los_Angeles, that is two schedules, two timezones, no DST math. Pick the IANA zone that matches the schedule's intent.

Step 8: Press "Perform test" and verify

Click Perform test. Crontap fires a real POST to the URL once. You should see:

  • A 200 in Crontap's run history.
  • A run entry in Bubble's server logs (Logs tab in the Bubble editor) for cron-poll-stripe.

If you see 401, your auth (bearer or shared secret) is mismatched. If you see 403, your Only when guard is rejecting the call. If you see 5xx, the workflow body itself failed and you can debug from Bubble's logs. Add a failure alert in Crontap (email / webhook (Slack / Discord / Telegram)) so the next 4xx or 5xx pings you immediately rather than waiting for someone to check the dashboard.

Move the scheduling overhead out of Bubble. Free tier available. No credit card. Schedule your first job →

Worked examples

Three concrete shapes that map onto the patterns teams ask about most.

Polling a third-party API every minute for 500 users

The shape from the r/Bubbleio thread on the 24-hour scheduling limit, cleaned up. A backend workflow poll-vendor reads 500 users, calls a vendor API for each, writes results back. One Crontap schedule, every-1-minute cadence, points at the workflow URL.

WU cost on the recursive native shape: 30,240 WU/month on Schedule API Workflow overhead alone, before the polling runs. WU cost on external cron: 0 on overhead, the polling itself bills the same WU it did before.

If your vendor rate-limits at 60 requests per minute, 500 users does not fit one iteration. Move the user list into the workflow body as a sub-loop with Schedule API Workflow on a list chunking 50 users per iteration. The outer Crontap schedule still fires every minute; Bubble bills the chunked work as normal actions.

5-minute appointment-reminder check across multiple timezones

A scheduling SaaS sends "your appointment is in 30 minutes" reminders to customers in Europe/London, America/New_York, America/Los_Angeles, Asia/Tokyo. Each timezone has quiet hours (no reminders 22:00 to 07:00 local).

Native shape: one recursive workflow that reads all appointments and runs a per-row quiet-hours check, even for rows in quiet hours, so the workflow body is thicker than it needs to be.

External cron shape: 4 Crontap schedules, one per timezone, each at */5 7-22 * * * in the matching IANA zone. The Bubble workflow body becomes "find appointments due in the next 30 minutes, send reminder". No quiet-hours guard, no DST math, no recursive overhead.

Hourly digest send for a Starter-plan app that needs to stay on Starter

A small app on Starter (175,000 WU/month) sends an hourly digest of new activity. The native shape would lean on Recurring event, which hits the Starter "1 recurring event per data thing" cap if schedules live on the User row.

External cron shape: one Crontap schedule, hourly cadence, points at a send-hourly-digest API workflow. No Recurring event instances, no per-thing limits, the Starter app stays on Starter.

Side by side: native recursive workflow vs external cron + API workflow

For the same minute-cadence job, here is the comparison.

WU cost (per month, every minute)

  • Native recursive: 30,240 WU bookkeeping + actual work. ~17% of Starter, before the work.
  • External cron: 0 WU bookkeeping + actual work. The work itself bills the same in both shapes.

Reliability across deploys, sleeps, and recursion-cap resets

  • Native recursive: a deploy can interrupt an in-flight chain. Free apps sleep; Starter and up do not sleep, but a recursion-cap reset stops the loop and needs a manual kick. The 10-iteration cap on new apps stops minute-level loops after 10 minutes silently.
  • External cron: schedule is independent of Bubble's deploy and sleep cycle. If Bubble is up, the next ping fires the workflow. If Bubble is down, Crontap retries on the next cadence. No iteration depth, no manual kick.

Visibility

  • Native recursive: Bubble's server logs only.
  • External cron: Bubble's server logs plus Crontap's per-call run history (HTTP status, response body, timing) in one dashboard. Failed runs alert to email / webhook (Slack / Discord / Telegram) the moment they happen.

Cancel and pause

  • Native recursive: open the Bubble Scheduler tab and cancel the next queued instance. If the workflow re-schedules itself before you cancel, you end up cancelling the new one instead of the loop.
  • External cron: open Crontap, click pause. Stops firing immediately, resumes on click.

How this compares to other "every minute on Bubble" options

Other paths show up in community threads. They all work; the trade-offs differ.

Webhook Scheduler Pro (paid Bubble plugin)

A marketplace plugin wrapping Google Cloud Tasks. The per-app pricing model means every Bubble app you own pays again. Fine for one app; the cost stacks if you run several or want a single dashboard across non-Bubble targets.

cron-job.org (free)

A free public cron service. Works for basic use. Limited run history, no team features (shared workspace, role-based access, audit trail). Fine for a side project; thin for a team.

Schedule by Zapier

Lives in your Zapier account. Per-task billing means a minute-cadence schedule is 43,200 tasks a month, which exits Zapier's free and Starter tiers fast. Schedule by Zapier also doesn't reach minute cadence below Team in Zapier's pricing.

Make.com or n8n

Both work. The trade-off is running a second automation tool to drive your first. Fine if you already run Make or n8n; heavy install for a 1-line cron otherwise.

When to keep using Bubble's native scheduler

External cron is a shape, not a religion. The native scheduler is the right answer for:

  • Daily-or-rarer recurring events that fit the native dropdown. The native scheduler is one tick.
  • Per-thing recurrence where each row has its own schedule. Bubble's Schedule API Workflow on a list is the cleanest expression of "fire this workflow once per user at their preferred time". External cron has to call back in for each row, which is more wiring.
  • "Run as admin / Ignore privacy rules" jobs you don't want exposed. Privacy-bypass actions can only run inside Bubble's runtime. "Delete every soft-deleted record older than 30 days as admin" is a native job.

For everything else (sub-daily, plan-cap-binding, multi-environment parity, per-IANA timezone, cross-vendor dashboard), external cron reads cleaner and bills cheaper.

FAQ

Will Crontap's call still consume my WU?

Only the workflow body, not the scheduling. Bubble bills the WU for the actions your workflow runs once it receives the request. The 0.7 WU per Schedule API Workflow call goes away because there is no Schedule API Workflow action in the path; Crontap fires the URL directly.

Can I trigger the same endpoint from version-test and version-live?

Yes. Two Crontap schedules, same shape, different URL prefix (version-live for prod, version-test for dev). Pause the dev schedule between sprints to save WU on the test environment; per-environment cadence and timezone stay independent.

How do I cancel an in-flight recursive workflow I've already deployed?

Open the Bubble editor, click the Scheduler tab, cancel queued instances. If the workflow keeps re-scheduling itself faster than you can cancel, deploy a version that strips the Schedule API Workflow step at the end of the body, then cancel the last queued instance. Then switch to the external cron shape so the loop stops self-perpetuating.

What happens if my Bubble app is sleeping (Free plan) when the cron fires?

Free apps sleep after inactivity. A Crontap call wakes the app; the first call may take longer (cold start), the second is normal. Crontap reports response time per call, so you can see whether wake-up latency matters. Paid plans (Starter and up) do not sleep.

Can I run sub-minute schedules?

Crontap's floor is every 1 minute on Pro. Sub-minute work tends to be event-driven, not time-driven, and is better served by a queue (BullMQ, SQS, Cloud Tasks). "Fire every 30 seconds for the next 10 minutes after a user action" is a job-fan-out problem, not a scheduling problem.

Move the scheduling overhead out of Bubble. Free tier available. 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.

Alternatives

Heroku Scheduler alternative: any cron expression without the add-on

Heroku Scheduler caps you at three cadences and account-wide UTC, and spins a one-off dyno per run. Here is the external cron pattern that gives you any cron expression, per-schedule timezones, and zero per-execution dyno spin-up cost.

Guides

Running an OpenAI sentiment pipeline on a real scheduler

OpenAI batch work needs a clock, not a user session. Here is the scheduled HTTP-route pattern teams use to drain LLM batches at a sustainable rate inside OpenAI's rate limits, with per-task failure alerts.

Reference

Cron syntax cheat sheet with real-world examples

Cron syntax without the math. Every pattern you're likely to reach for (every 5 minutes, weekdays, business hours, first of the month), with a practical example and a link to a free debugger.