No-Server Scheduling Tool: A Complete Guide to cron-job.org

In the previous section, we learned how to use Crontab locally. But what if you don’t have a server running 24/7?

If you’ve already deployed your website or API to a free PaaS platform (like Render, Heroku, or Vercel), these platforms may not offer free "background scheduled tasks," or even if they do, the free tier comes with strict limitations (e.g., the server goes to sleep after 15 minutes of inactivity).

This is where cron-job.org comes to the rescue!

What Is Webhook Scheduling?

The principle behind cron-job.org is simple. It’s essentially a server located in Europe. You give it a URL and a time interval, and when the time comes, this server will access the URL you specified (like an invisible user opening a browser for you).

Once your URL (API) is accessed, your backend server will execute the code you’ve written. This is known as the Webhook trigger mechanism.

[!TIP] Common Use Case: Preventing Free Server Sleep (Keep-alive) Many free platforms (like Render) will "shut down" your server to save resources if there are no HTTP requests for 15 minutes. The next time someone visits, it can take up to 50 seconds to boot up (cold start). We can use cron-job.org to ping your homepage every 10 minutes. This way, your free server will stay "awake" forever, giving you premium service without spending a dime!

Registering and Creating Your First Cronjob

1. Register an Account

First, go to cron-job.org and click Sign Up in the top-right corner to register a free account. This is a non-profit service that has been running stably for over a decade—very generous.

2. Create a New Task (Create Cronjob)

After logging in, click the "CREATE CRONJOB" button.

You’ll see several fields to configure:

  • Title: Give your task a name, e.g., "Keep-alive Task for Check-in Bot."
  • URL: Enter the API URL you want to trigger, e.g., https://my-fastapi-app.onrender.com/api/daily-task.
  • Execution Schedule: The interface here is very intuitive! You can set the frequency with just a few clicks:
    • Every minute
    • Every 5 minutes
    • User-defined: If you choose custom, the interface is very similar to the Crontab we learned in the previous section, allowing you to select specific months, days, and times.

3. Advanced Settings

For basic "keep-alive tasks," the above settings are usually enough. But if you’re triggering a sensitive API that modifies data, you might need advanced settings:

  • HTTP Method: Default is GET. If your backend API is designed to accept POST requests, you can change the method here.
  • Headers: To prevent random hackers from spamming your scheduled API and causing duplicate executions, you should add custom authentication here. For example, add:
    • Key: Authorization
    • Value: Bearer my_super_secret_token_123
  • Request Body: For POST requests, you can also include JSON data to send to your backend.

4. Save and Monitor

Once configured, click CREATE at the bottom, and your schedule will start running!

In the cron-job.org dashboard, you can clearly see the success/failure history of past executions. If your API returns an error (e.g., 500), it will log the server’s error message and can even email you a warning if the task fails!

Practical Example: FastAPI Endpoint Design

If you’re using cron-job.org, your backend code (using Python FastAPI as an example) might look like this:

from fastapi import FastAPI, Depends, HTTPException, Header
import os

app = FastAPI()

# Get the secret key from environment variables
CRON_SECRET = os.getenv("CRON_SECRET", "my_super_secret_token_123")

def verify_cron_token(authorization: str = Header(None)):
    """Verify if the request is from cron-job.org"""
    if authorization != f"Bearer {CRON_SECRET}":
        raise HTTPException(status_code=401, detail="Unauthorized Request")
    return True

@app.post("/api/daily-task")
async def run_daily_task(authorized: bool = Depends(verify_cron_token)):
    """
    This API will be called daily by cron-job.org
    """
    print("Starting daily task...")
    
    # Write your business logic here
    # E.g., fetch reports from the database, send Line notifications, clean expired data, etc.
    
    return {"status": "success", "message": "Daily task completed."}

[!IMPORTANT] Security First! If your Webhook API writes data or sends messages, never leave it publicly accessible without authentication. Malicious bots scan URLs constantly, and if yours is found, your API could be spammed thousands of times a day, crashing your database or sending endless spam. Always use a token for protection, as shown in the example above.

With cron-job.org and your backend API, you’ve solved 80% of your scheduled task needs—without adding any server costs!

Request Types and Methods

| HTTP Method | Typical Use | Auth Needed | |-------------|-------------|-------------| | GET | Keep-alive ping, read-only checks | Optional | | POST | Data processing, writes | Required | | PUT | Resource updates | Required | | DELETE | Cleanup tasks | Required |

Choosing the Right Method

# GET: simple keep-alive (no request body needed)
@app.get("/ping")
async def keep_alive():
    return {"status": "alive", "timestamp": datetime.now().isoformat()}

# POST: daily task with authentication
@app.post("/api/daily-task")
async def daily_task(authorization: str = Header(None)):
    if authorization != f"Bearer {os.getenv('CRON_SECRET')}":
        raise HTTPException(status_code=401, detail="Unauthorized")
    # Execute business logic
    return {"status": "success"}

Cron-Job.Org Dashboard

The dashboard provides execution history, logs, and notifications.

Features

| Feature | Free Tier | Description | |---------|-----------|-------------| | Cronjobs | Unlimited | Create as many as you need | | Execution logs | 7 days | View success/failure history | | Email alerts | Yes | Get notified on failures | | HTTP methods | All | GET, POST, PUT, DELETE | | Custom headers | Yes | Authentication tokens | | Request body | Yes | JSON or form data |

Monitoring Your Tasks

# Use curl to test your API endpoint manually
curl -X POST https://my-app.onrender.com/api/daily-task \
  -H "Authorization: Bearer my_secret_token" \
  -H "Content-Type: application/json" \
  -d '{"test": true}'

# Expected response
# {"status": "success", "message": "Daily task completed."}

Use Case: Free Server Keep-Alive

Many free platforms (Render, Heroku, Fly.io) put servers to sleep after inactivity. Cron-job.org can prevent this.

Platform Sleep Policies

| Platform | Idle Timeout | Cold Start | |----------|-------------|------------| | Render Free | 15 minutes | ~30-50 seconds | | Heroku Free | 30 minutes | ~5-10 seconds | | Fly.io | Varies by config | ~5 seconds |

Keep-Alive Configuration

# Recommended cron-job.org settings
Title: My-App Keep-Alive
URL: https://my-app.onrender.com/ping
Schedule: Every 10 minutes
Method: GET

Advanced: Multiple Tasks

# backend/main.py
from fastapi import FastAPI, Header, HTTPException
import os

app = FastAPI()
SECRET = os.getenv("CRON_SECRET")

def verify(headers):
    auth = headers.get("authorization")
    if auth != f"Bearer {SECRET}":
        raise HTTPException(401, "Unauthorized")

@app.get("/api/keep-alive")
async def keep_alive():
    return {"status": "ok", "time": datetime.now().isoformat()}

@app.post("/api/daily-report")
async def daily_report(authorization: str = Header(None)):
    verify(authorization)
    # Generate and send daily report
    return {"status": "success", "report": "sent"}

@app.post("/api/cleanup")
async def cleanup(authorization: str = Header(None)):
    verify(authorization)
    # Delete old records
    return {"status": "success", "deleted": 42}

Troubleshooting

If your cron job isn't executing as expected:

| Problem | Cause | Solution | |---------|-------|----------| | No execution | URL incorrect | Double-check the URL | | 404 error | Endpoint doesn't exist | Verify route path | | 401 error | Wrong auth token | Check Authorization header | | 500 error | Server crash | Check server logs | | Timeout | Server too slow | Reduce response time | | No log shown | Refresh delay | Wait 1-2 minutes |

Verification Steps

  1. Test the URL with curl before adding to cron-job.org
  2. Check the execution history in the dashboard
  3. Enable email alerts for failure notifications
  4. Verify your server is awake (not sleeping)

Summary

Cron-job.org provides free, reliable webhook scheduling. It pings your API endpoints on a schedule, making it ideal for keep-alive, daily tasks, and automation — all without a dedicated server.

Key takeaways:

  • Cron-job.org is a free webhook scheduling service running for over a decade |
  • It pings your URL on a schedule, triggering your backend code |
  • Always authenticate write operations with a token |
  • Dashboard shows execution history with success/failure logs |
  • Great for keep-alive: ping every 10 minutes to prevent sleep |
  • Supports GET, POST, PUT, DELETE with custom headers and body |
  • Test your API with curl before configuring the cronjob |
  • Email alerts notify you when tasks fail |

What's Next: GitHub Actions Cron

The next chapter covers GitHub Actions for scheduled tasks — a powerful alternative built into your GitHub repository. EOF

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!