Scheduling Syncs

Set up automated syncs so your search performance data stays fresh without manual intervention.

Recommended frequency

A daily sync is ideal. Google Search Console data has a 2-3 day delay, so running once daily ensures you always have the most recent available data. Running more frequently provides no additional data.

Using cron

Add a cron job to run the sync daily at 2 AM:

# Edit crontab
crontab -e

# Add this line (runs daily at 2:00 AM)
0 2 * * * cd /path/to/your/project && pnpm pagebridge sync --site sc-domain:example.com >> /var/log/pagebridge-sync.log 2>&1
bash

Using GitHub Actions

Create a workflow file for automated syncs:

.github/workflows/pagebridge-sync.yml
name: PageBridge Daily Sync

on:
  schedule:
    - cron: '0 2 * * *'  # Daily at 2:00 AM UTC
  workflow_dispatch:       # Allow manual triggers

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Run PageBridge sync
        run: pnpm pagebridge sync --site sc-domain:example.com --check-index
        env:
          GOOGLE_SERVICE_ACCOUNT: ${{ secrets.GOOGLE_SERVICE_ACCOUNT }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
          SANITY_PROJECT_ID: ${{ secrets.SANITY_PROJECT_ID }}
          SANITY_DATASET: ${{ secrets.SANITY_DATASET }}
          SANITY_TOKEN: ${{ secrets.SANITY_TOKEN }}
          SITE_URL: ${{ secrets.SITE_URL }}
yaml

Setting up GitHub Secrets

In your GitHub repository, go to Settings > Secrets and variables > Actions and add each environment variable as a secret.

Using Vercel Cron

If your site is deployed on Vercel, you can create an API route that triggers the sync and schedule it with Vercel Cron:

app/api/cron/pagebridge-sync/route.ts
import { SyncEngine, GSCClient, DecayDetector, URLMatcher, TaskGenerator } from '@pagebridge/core'
import { createDb } from '@pagebridge/db'
import { createClient } from '@sanity/client'

export async function GET(request: Request) {
  // Verify the request is from Vercel Cron
  const authHeader = request.headers.get('authorization')
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response('Unauthorized', { status: 401 })
  }

  // Run sync...
  const gsc = new GSCClient({
    credentials: JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT!)
  })
  const db = createDb(process.env.DATABASE_URL!)
  const sanity = createClient({
    projectId: process.env.SANITY_PROJECT_ID!,
    dataset: process.env.SANITY_DATASET!,
    token: process.env.SANITY_TOKEN!,
    apiVersion: '2024-01-01',
    useCdn: false
  })

  const engine = new SyncEngine({ gsc, db, sanity })
  const result = await engine.sync({ siteUrl: 'sc-domain:example.com' })

  return Response.json({ success: true, pages: result.pages.length })
}
typescript
vercel.json
{
  "crons": [
    {
      "path": "/api/cron/pagebridge-sync",
      "schedule": "0 2 * * *"
    }
  ]
}
json

Multiple sites

If you manage multiple GSC properties, run separate sync commands for each:

pagebridge sync --site sc-domain:example.com
pagebridge sync --site sc-domain:other-site.com
bash

See Multi-site setup for more details.