Skip to content

Schedules

ProLearn more about Pro
NotebooksLearn about notebooks vs. projects

You can set your notebooks to run on Observable’s servers every day, every hour, or every ten minutes. This is especially designed for use with Notifications so you can send periodic charts, data, and other alerts to email or Slack. But you can also do anything else an Observable notebook can do, including querying databases or accessing APIs.

Note

This feature is in public beta. Cloud files don’t currently work in scheduled notebook runs. Contact support@observablehq.com with any questions.

To schedule a notebook, open the Schedule sidebar pane and select a schedule:

ScheduleTiming
Run every ten minutes
Run every houraround :00
Run every dayaround 11 AM UTC (6 AM EST / 3 AM PST)

In the sidebar you can view previous runs, including whether it completed with or without errors. Click a run to see its logs, which capture console messages and errors from your notebook.

Sidebar pane labeled Schedule with no schedule set

The battery icon in the upper right shows how many minutes of runtime you have remaining this calendar month. Notebooks running in the cloud take time, and we cap the amount of time you can use per month at 50 minutes per editor or owner in your workspace. The battery icon in the upper right of the sidebar shows you how much time you have remaining. Please email support@observablehq.com if you need more time.

You can see all currently scheduled notebooks and a summary of their recent errors in your workspace settings on the Schedules tab.

Data policy

Without schedules, the code in notebooks runs only on your own computer when you visit the notebook; see our security model for details. When you schedule a notebook, it also runs periodically on Observable’s servers in the cloud, and we temporarily store limited logs related to it:

  1. Console messages (like console.log and console.error)
  2. JavaScript errors (like syntax and reference errors)
  3. Network errors (like if you fetch a resource that returns a 404 error)

We have tried to log only what we need to provide you with a usable debugging experience. Those logs are only accessible to the same users who can view the notebook with that code. If you remove access to the notebook (e.g. change it from being shared with your team to only shared with one person), then the permissions of new and existing logs are also updated to match. You can only access the last 30 days of logs.

Tips

Your notebook has 5 minutes (300 seconds) to run

Notebooks are allowed 5 minutes to complete their work when run by our servers on a schedule. If you hit the cap you’ll get Error: Timeout after 300000ms.

You can run code at more specific times

Though we only offer three preset frequencies, you can add logic so that code only runs at more specific times (the scheduler runs in UTC). E.g., only if it’s a Monday:

js
{
  if (new Date().getDay() === 1 /* Monday */) {
    return (await NotificationClient("email:you@example.com")).send("Happy Monday!")
  }
}

You can run code differently in the scheduler

Your code can check if it’s currently running in the cloud, as opposed to being run by a person in a browser.

js
{
  if (currentUser.login === "scheduler") {
    // Notebook is running in the cloud
  }
}

Remember to await or return promises

If you’re looking at a notebook in the browser, this cell will log its message to the console after 5 seconds:

js
{
  Promises.delay(5000).then(() => console.log("It’s been five seconds"))
}

But, when run in the scheduler, it probably won’t log anything. The scheduler is impatient by design: it waits for every cell to resolve and then immediately quits running your notebook, to use as little of your cloud compute quota as possible. The cell above immediately returns undefined; it doesn’t return the promise, so we don’t await it, and the notebook stops running before the message can be logged (unless it’s still waiting for a different cell). This is a common reason why you may see a notification send in the browser but not in the scheduler (read more).

Instead, return the promise:

js
{
  return Promises.delay(5000).then(() => console.log("It’s been five seconds"))
}

Or use an expression that evaluates to the promise:

js
Promises.delay(5000).then(() => console.log("It’s been five seconds"))