Skip to main content

Devpost Scraper

CLI toolkit for extracting Devpost hackathon data, enriching participants with emails, storing results in SQLite, and emitting Customer.io events.

Three commands:

Command Purpose
devpost-scraper Search Devpost projects by keyword, enrich with emails, export CSV
devpost-participants Scrape a single hackathon's participant list, export CSV
devpost-harvest Walk the hackathon listing, scrape all participants, store in SQLite, emit delta events

Requirements

  • Python 3.11+
  • uv
  • A Backboard API key (for devpost-scraper only)

Install

uv sync

Environment

Copy .env.example → .env and fill in:

Variable Required for Notes
BACKBOARD_API_KEY devpost-scraper Backboard account key
DEVPOST_ASSISTANT_ID auto Persisted on first run
DEVPOST_SESSION devpost-participants, devpost-harvest _devpost cookie from browser DevTools
GITHUB_TOKEN optional GitHub PAT for 5000 req/hr (vs 60). No scopes needed
CUSTOMERIO_SITE_ID --emit-events Customer.io Track API
CUSTOMERIO_API_KEY --emit-events Customer.io Track API

devpost-scraper

Search Devpost projects by keyword, enrich each with detail page + author email, export CSV.

uv run devpost-scraper "ai agents" --output results.csv
uv run devpost-scraper "climate tech" "developer tools" -o results.csv

# Or via start.sh
./start.sh "ai agents" --output results.csv

devpost-participants

Scrape a single hackathon's participant list and export to CSV.

# First time — pass session cookie
uv run devpost-participants "https://authorizedtoact.devpost.com/participants" \
  --jwt "<_devpost cookie value>" -o participants.csv

# Reuse saved session from .env
uv run devpost-participants "https://authorizedtoact.devpost.com/participants" -o out.csv

# Skip email enrichment
uv run devpost-participants "https://..." --no-email -o out.csv

# Emit Customer.io events after scrape
uv run devpost-participants "https://..." --emit-events -o out.csv

devpost-harvest

Automated pipeline: walk the hackathon listing → scrape participants → store in SQLite → emit Customer.io events for delta (new) participants.

Basic usage

# Scrape 3 pages of open hackathons (27 hackathons), enrich new participants, emit events
uv run devpost-harvest --emit-events

# Fast first run — scrape without email enrichment
uv run devpost-harvest --no-email

Flags

Flag Default Description
--pages N 3 Number of hackathon listing pages to fetch (9 per page)
--hackathons N 0 (all) Only process the first N hackathons from the listing
--jwt TOKEN .env Devpost _devpost session cookie
--db PATH devpost_harvest.db SQLite database path
--status {open,ended,upcoming} open Hackathon status filter (repeatable)
--max-participants N 0 (unlimited) Cap participants scraped per hackathon
--no-email off Skip email enrichment entirely (even for new participants)
--emit-events off Emit Customer.io events for unemitted participants during scrape
--emit-unsent off Skip scraping — just emit events for all unsent participants in DB
--rescrape off Re-scrape hackathons already scraped in a previous run

How it works

Phase 1: Discover hackathons
  GET /api/hackathons?status[]=open → paginated JSON listing

Phase 2: Per hackathon
  2a. Fast scan — scrape all participant pages (no enrichment, ~1 req per 20 participants)
  2b. Upsert into SQLite → detect delta (new participants not previously in DB)
  2c. Email-enrich delta only — GitHub API + link walking (skipped with --no-email)
  2d. Emit Customer.io events for unemitted participants (only with --emit-events)

Delta logic

On subsequent runs, the fast scan re-fetches participant lists but only new participants (not previously in SQLite) get the expensive email enrichment. Already-emitted participants are never re-emitted. This makes re-runs fast and safe to repeat.

Common workflows

# Initial bulk scrape (no events yet)
uv run devpost-harvest --pages 5

# Emit all unsent events from the DB (no scraping, no JWT needed)
uv run devpost-harvest --emit-unsent

# Quick delta check on first hackathon only
uv run devpost-harvest --hackathons 1 --rescrape --emit-events

# Re-scan all hackathons for new participants, enrich + emit
uv run devpost-harvest --rescrape --emit-events

# Include ended hackathons
uv run devpost-harvest --status open --status ended

# Fast delta scan (skip email enrichment for new participants too)
uv run devpost-harvest --rescrape --no-email

SQLite schema

The database (devpost_harvest.db) has two tables:

  • hackathons — id, url, title, org, state, dates, registrations, prize, themes. last_scraped_at is set after participants are scraped.
  • participants — (hackathon_url, username) primary key, enrichment fields, first_seen_at, last_seen_at, event_emitted_at.

Customer.io events

Event name: devpost_hackathon. Uses participant email as the Customer.io user ID.

Event data: hackathon_url, hackathon_title, username, name, specialty, profile_url, github_url, linkedin_url.

Email templates in emails/ use {{customer.first_name}} and {{event.*}} Liquid variables.


Development

uv run python -m devpost_scraper.cli "ai agents" --output out.csv

Metadata

Release files for devpost-scraper 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for devpost-scraper 0.3.0
File Size Uploaded
devpost_scraper-0.3.0.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for devpost-scraper 0.3.0
File Interpreter ABI Platform
devpost_scraper-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.6 kB

Release files / devpost_scraper-0.3.0.tar.gz

Download URL devpost_scraper-0.3.0.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
10563140ec7cc50b1d702e895e888e54ddd4232fce9d94b4fcd297d0116438d7
BLAKE2b-256 checksum
How to use checksums
0e7a23ea56b84a78d7d82db6d00aef7a711089356a96124b7ed068a2d09b7b3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release files / devpost_scraper-0.3.0-py3-none-any.whl

Download URL devpost_scraper-0.3.0-py3-none-any.whl
Size 21.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ad1af87254081bd49889060cdc48cd47d237c25f7b8d2667a720d5c109e4b38d
BLAKE2b-256 checksum
How to use checksums
63fffce410ab55012e489c87abf80eafb1d9381ba52fa7ebe1098c30fb327869
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page