# How to Schedule Rank Tracking Tasks in OpenSEO: A Complete Guide

> Learn how to schedule rank tracking tasks in OpenSEO. Automate SERP rank checks with daily, weekly, or monthly intervals for efficient SEO monitoring.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-09-09

---

**OpenSEO lets you automate SERP rank checks by configuring a `scheduleInterval` of `daily`, `weekly`, `monthly`, or `manual` on your rank-tracking configurations, with a Cloudflare Worker cron processing due tasks every 5 minutes.**

OpenSEO (from the `every-app/open-seo` repository) provides a robust automation system for monitoring search engine rankings across different domains, locations, and devices. When you schedule rank tracking tasks in OpenSEO, the system handles execution timing, budget enforcement, and next-run calculation automatically through a serverless architecture.

## Understanding Schedule Intervals

OpenSEO supports four distinct scheduling intervals that determine how frequently the system checks your keyword rankings:

| Interval | Execution Frequency | Approximate Monthly Checks |
|----------|-------------------|---------------------------|
| `daily` | Once every day | ~30 checks |
| `weekly` | Once every week | ~4 checks |
| `monthly` | Last day of each month | 1 check |
| `manual` | No automatic execution | User-triggered only |

When you create a rank-tracking configuration with any non-`manual` interval, the system calculates the next check time and stores it in the `nextCheckAt` field.

## Creating a Scheduled Rank Tracking Configuration

To schedule rank tracking tasks in OpenSEO, use the `createRankTrackingConfig` server function located in [`src/serverFunctions/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/rank-tracking.ts). This function accepts a `scheduleInterval` parameter alongside your targeting criteria.

```typescript
import { createRankTrackingConfig } from "@/serverFunctions/rank-tracking";

await createRankTrackingConfig({
  domain: "example.com",
  locationCode: "us",
  languageCode: "en",
  locationName: "United States",
  devices: "both",
  serpDepth: 30,
  scheduleInterval: "weekly",   // ⬅️ set the schedule here
});

```

For fresh configurations, the system automatically selects a random hour between 04:00 and 09:00 UTC on the appropriate day to distribute load and avoid spikes.

## Updating or Removing Schedules

You can modify the schedule of an existing configuration using `updateRankTrackingConfig` from the same module. Pass the `configId` and new `scheduleInterval` to change the frequency without affecting other settings.

```typescript
import { updateRankTrackingConfig } from "@/serverFunctions/rank-tracking";

await updateRankTrackingConfig({
  configId: "cfg_abc123",
  scheduleInterval: "daily",   // switch to daily checks
  // other fields can be omitted if unchanged
});

```

## The Scheduling Engine: How It Works

The core scheduling logic resides in [`src/shared/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/rank-tracking.ts) and [`src/server/features/rank-tracking/services/scheduledRankChecks.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/scheduledRankChecks.ts).

### Computing Next Run Times

The `computeNextCheckAt` function calculates when the next rank check should occur based on the interval and previous execution:

1. Takes the interval (`daily`, `weekly`, or `monthly`) and the previous `nextCheckAt` timestamp
2. Advances the anchor date until the computed time is in the future, preventing drift from delayed runs
3. For new configs, randomizes the hour between 04:00 and 09:00 UTC

```typescript
import { computeNextCheckAt } from "@/shared/rank-tracking";

const next = computeNextCheckAt("weekly", "2024-09-01T04:00:00.000Z");
// → "2024-09-08T04:00:00.000Z"

```

### The Cloudflare Worker Cron

Every 5 minutes, a Cloudflare Worker executes the `runScheduledRankChecks` routine defined in [`src/server/features/rank-tracking/services/scheduledRankChecks.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/scheduledRankChecks.ts). This function:

- Queries all configurations where `nextCheckAt` has passed
- Validates paid plan status (unpaid projects are skipped with `RankTrackingSkipReason` stored)
- Respects per-tick budget constraints
- Initiates rank-check runs for due configurations
- Updates `nextCheckAt` for the next interval

```typescript
import { runScheduledRankChecks } from "@/server/features/rank-tracking/services/scheduledRankChecks";

export default {
  async scheduled(env: Env) {
    await runScheduledRankChecks(env);
  },
};

```

## Manual Triggers for Ad-Hoc Checks

For configurations set to `manual` or when you need immediate data, use the `triggerRankCheck` function. This bypasses the scheduling system and starts a check immediately.

```typescript
import { triggerRankCheck } from "@/serverFunctions/rank-tracking";

await triggerRankCheck({
  configId: "cfg_abc123",
  keywordIds: [],   // empty → check all keywords in the config
});

```

## Paid Plan Requirements

The scheduling system enforces business logic through the `RankTrackingService` in [`src/server/features/rank-tracking/services/RankTrackingService.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/RankTrackingService.ts). If a project lacks a paid subscription during a scheduled tick, the task is skipped and flagged with a "plan required" badge in the UI. The specific skip reason is recorded in the `RankTrackingSkipReason` field, allowing you to audit why checks did not execute.

## Summary

- **OpenSEO supports four intervals**: `daily` (~30/month), `weekly` (~4/month), `monthly` (1/month), and `manual` (on-demand).
- **Create schedules** using `createRankTrackingConfig` in [`src/serverFunctions/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/rank-tracking.ts) with the `scheduleInterval` parameter.
- **The scheduling engine** uses `computeNextCheckAt` (in [`src/shared/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/rank-tracking.ts)) to calculate next run times and prevent drift.
- **Execution** is handled by a Cloudflare Worker running `runScheduledRankChecks` every 5 minutes from [`src/server/features/rank-tracking/services/scheduledRankChecks.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/services/scheduledRankChecks.ts).
- **Manual overrides** are available via `triggerRankCheck` for immediate data collection.
- **Paid plans are required** for automatic execution; unpaid projects are skipped and logged in `RankTrackingSkipReason`.

## Frequently Asked Questions

### How often does OpenSEO check for scheduled rank tracking tasks?

The Cloudflare Worker cron executes every 5 minutes, querying the database for configurations where the `nextCheckAt` timestamp has passed. If your schedule is set to `daily`, the system ensures at least 24 hours pass between checks, but the actual execution may occur within a 5-minute window of the scheduled time.

### Can I change a rank tracking schedule from automatic to manual?

Yes. Use the `updateRankTrackingConfig` function from [`src/serverFunctions/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/rank-tracking.ts) and set `scheduleInterval` to `"manual"`. The system will stop automatic executions immediately, though any already-queued runs may complete. You can then trigger checks manually using `triggerRankCheck` whenever needed.

### Why are my scheduled rank checks showing a "plan required" badge?

OpenSEO requires an active paid subscription to execute automatic rank checks. If your project is on a free plan when the `runScheduledRankChecks` worker processes your configuration, it skips the execution and stores the reason in the `RankTrackingSkipReason` field. Upgrade your plan and the next cron tick will process your scheduled tasks normally.

### What happens if a scheduled run is delayed or fails?

The `computeNextCheckAt` function in [`src/shared/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/rank-tracking.ts) is designed to handle drift. When calculating the next run time, it advances the anchor date from the previous `nextCheckAt` until the result is in the future, ensuring your schedule maintains its cadence (daily, weekly, monthly) regardless of when the previous run actually executed.