# RunSignup Race Scraper (`hypebridge/runsignup-race-scraper`) Actor

Extracts public race listings, sub-events, registration fee ladders, price-change dates, race information sections, and sponsor rosters from RunSignup.

- **URL**: https://apify.com/hypebridge/runsignup-race-scraper.md
- **Developed by:** [Hypebridge](https://apify.com/hypebridge) (community)
- **Categories:** Automation, Travel, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 basic races

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does RunSignup Race Scraper do?

**RunSignup Race Scraper** extracts public race listings, sub-events, registration fee ladders, price-change dates, race information sections, and sponsor rosters from [RunSignup](https://runsignup.com/). It accepts RunSignup search pages and individual race pages, plus equivalent TriSignup, BikeSignup, and GiveSignup URLs.

Use it to build race calendars, watch registration prices, research endurance-event markets, find sponsorship opportunities, or maintain a structured race directory. Results are saved as one record per race, with sub-events and sponsors nested inside it.

### What race data can it extract?

| Data | Description |
|---|---|
| Race identity | Name, canonical URL, race ID, logo, and public contact-form link |
| Dates and location | Next and previous dates, timezone, street, city, state, ZIP code, and country |
| Registration | Open status, event-level registration windows, current price, next price, and price-change date |
| Sub-events | Event name, type, distance, start/end time, giveaway options, and returning-event links |
| Race information | Description plus sections such as packet pickup, maps, parking, and results |
| Public links | Organizer website, results URL, and public Facebook identifiers when available |
| Sponsors | Sponsor name, website, logo, and ID when sponsor lookup is enabled |

The `sponsors` field deliberately distinguishes three states: `null` means no lookup was requested, `[]` means the race was checked and has no sponsors, and a populated array contains the confirmed sponsor roster.

### How to scrape RunSignup races

1. Open **RunSignup Race Scraper** in Apify.
2. Keep the default `https://runsignup.com/Races` URL or paste a filtered search/race URL.
3. Set **Maximum races** to control the amount of data and cost.
4. Enable **Get sponsor rosters** only when you need sponsor data; those checks are intentionally sequential and take longer.
5. Click **Start**, then download the Dataset as JSON, CSV, Excel, or HTML.

Large searches are automatically divided into bounded geographic and date windows so the actor can continue beyond RunSignup's per-query result ceiling. The global `maxRaces` cap always applies across every input URL.

### Input examples

Search California races in a date window:

```json
{
  "startUrls": [{ "url": "https://runsignup.com/Races?state=CA" }],
  "startDate": "2026-10-01",
  "endDate": "2026-12-31",
  "maxRaces": 500,
  "getSponsors": false
}
```

Search several regions for selected disciplines:

```json
{
  "startUrls": [{ "url": "https://runsignup.com/Races" }],
  "states": ["IL", "IN", "WI"],
  "eventTypes": ["running_race", "trail_race"],
  "maxRaces": 1000
}
```

Get one race with its sponsor roster:

```json
{
  "startUrls": [{ "url": "https://runsignup.com/Race/IL/Chicago/ExampleCityMarathon" }],
  "maxRaces": 1,
  "getSponsors": false
}
```

Direct race URLs are always fetched as detailed records and always include a sponsor check, regardless of the global sponsor toggle.

### Input reference

| Parameter | Default | Description |
|---|---:|---|
| `startUrls` | RunSignup races directory | Up to 100 search or race URLs |
| `maxRaces` | `100` | Global unique-race cap; maximum 50,000 |
| `getSponsors` | `false` | Perform bounded sponsor checks for discovered races |
| `states` | `[]` | Two-letter US state or Canadian province codes |
| `country` | `US` | Region set and output post-filter: `US`, `CA`, or `any` |
| `startDate`, `endDate` | today, +1 year | Absolute or relative date window |
| `eventTypes` | `[]` | One or more RunSignup discipline filters |
| `nameQuery` | — | Race-name filter for search inputs |
| `minDistance`, `maxDistance` | — | Numeric distance bounds |
| `zipcode`, `radius` | —, `25` | US ZIP-centred radius search |
| `modifiedSince` | — | Incremental refresh filter |
| `includeInfoSections` | `true` | Include public information sections at no extra request cost |
| `maxSponsorLookups` | `200` | Hard run-duration guard for sponsor checks |

Optional RunSignup API credentials can be supplied as a secret key/secret pair. The actor verifies their available pagination capability at run start and safely falls back to partitioned discovery when necessary.

### Output example

```json
{
  "raceId": 123456,
  "name": "Example City Marathon",
  "url": "https://runsignup.com/Race/IL/Chicago/ExampleCityMarathon",
  "sourceMode": "search",
  "nextDate": "2026-10-18T00:00:00.000-05:00",
  "address": {
    "city": "Chicago",
    "state": "IL",
    "countryCode": "US"
  },
  "eventCount": 2,
  "minCurrentPrice": 35,
  "maxCurrentPrice": 85,
  "nextRacePriceIncreaseAt": "2026-09-15T00:00:00.000-05:00",
  "events": [
    {
      "eventId": 654321,
      "name": "Half Marathon",
      "distance": "13.1 Miles",
      "currentPrice": 75,
      "nextPrice": 85,
      "priceIncreaseAmount": 10,
      "registrationStatus": "open"
    }
  ],
  "sponsors": null,
  "scrapedAt": "2026-09-04T12:00:00.000Z"
}
```

### How much does it cost?

This actor uses pay-per-event pricing. The current dollar price for each event is shown in the Apify run console before you start.

| Event | Charged when |
|---|---|
| `race-basic` | A race is saved without a completed sponsor lookup |
| `race-detailed` | A race is saved after its requested sponsor check, including a confirmed no-sponsors result |

Duplicates, drafts, invalid records, failed writes, and failed direct URLs are not charged. Use `maxRaces` and `maxSponsorLookups` as firm spend and runtime controls.

### Tips and limitations

- Use filtered search URLs or `states` for targeted runs; broad searches are complete within the configured date window but require more requests.
- Sponsor checks follow RunSignup's one-request-per-second race-page policy and are usually the slowest part of a run.
- Fee timestamps are evaluated in each race's local timezone, so current and upcoming prices stay accurate around midnight.
- This is a public race-prospecting feed, not a race-director email database. Organizer contact is routed through RunSignup's public contact form.
- A very dense state/day can still exceed 1,000 races. The actor reports that rare truncation instead of recursing without a bound.

### FAQ

#### Can I scrape one RunSignup race page?

Yes. Paste any supported race, information, events, sponsors, or registration URL. The actor resolves it to the canonical race, returns full event details, and checks sponsors.

#### Does it support TriSignup and BikeSignup links?

Yes. TriSignup, BikeSignup, and GiveSignup links are accepted and normalized to the canonical RunSignup race record.

#### Is scraping RunSignup legal?

The actor extracts publicly available race data. Always review the source site's terms and applicable laws, and use the data for a legitimate purpose.

### Support

- Report bugs or feature requests in the **Issues** tab.
- Use the **API** tab for programmatic runs and integrations.

> **Disclaimer:** This actor extracts public information only. Public results may still contain personal data protected by privacy laws. Do not collect or use personal data without a legitimate legal basis; consult qualified counsel if you are unsure.

# Actor input Schema

## `startUrls` (type: `array`):

RunSignup search URLs or race URLs, including /Race/Info/, /Race/Events/, /Race/Sponsors/, and /Race/Register/. TriSignup, BikeSignup, and GiveSignup URLs are accepted.

## `maxRaces` (type: `integer`):

Global maximum number of unique races returned across all start URLs and query partitions.

## `getSponsors` (type: `boolean`):

Fetch each race's sponsor list. This uses sequential race-page checks and is billed at the detailed rate. Direct race URLs always include sponsors.

## `nameQuery` (type: `string`):

Filter search inputs by race name.

## `states` (type: `array`):

Two-letter state or province codes. Leave empty to cover every region in the selected country.

## `country` (type: `string`):

Selects the region list and post-filters records by country.

## `startDate` (type: `string`):

Earliest race date as YYYY-MM-DD or a relative period such as 1 month.

## `endDate` (type: `string`):

Latest race date as YYYY-MM-DD or a relative period. Defaults to one year after the start date.

## `eventTypes` (type: `array`):

Discipline filters. Leave empty for every type.

## `minDistance` (type: `integer`):

Numeric minimum event distance in the selected units.

## `maxDistance` (type: `integer`):

Numeric maximum event distance in the selected units.

## `distanceUnits` (type: `string`):

Units used by the minimum and maximum distance filters.

## `zipcode` (type: `string`):

US ZIP code at the centre of a radius search.

## `radius` (type: `integer`):

Miles around the ZIP code. Ignored when no ZIP code is set.

## `modifiedSince` (type: `string`):

Return only races changed since this date, as YYYY-MM-DD or a relative period.

## `onlyRacesWithResults` (type: `boolean`):

Limit search inputs to races that report published results.

## `includeInfoSections` (type: `boolean`):

Include free-text race sections such as packet pickup, course maps, and results. This costs no extra requests.

## `maxSponsorLookups` (type: `integer`):

Hard cap on sequential sponsor checks per run. Direct race URLs are always checked and raise this cap when needed.

## `apiKey` (type: `string`):

Optional RunSignup API key. Supply it together with the API secret.

## `apiSecret` (type: `string`):

Optional RunSignup API secret. Supply it together with the API key.

## `maxConcurrency` (type: `integer`):

Simultaneous RunSignup data requests. The maximum of two follows RunSignup's published policy.

## `debugMode` (type: `boolean`):

Log partition filters and store a bounded set of sanitized failed-response artifacts.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://runsignup.com/Races"
    }
  ],
  "maxRaces": 1000,
  "getSponsors": false,
  "states": [],
  "country": "US",
  "startDate": "2026-09-03",
  "endDate": "1 year",
  "eventTypes": [],
  "distanceUnits": "K",
  "radius": 25,
  "onlyRacesWithResults": false,
  "includeInfoSections": true,
  "maxSponsorLookups": 200,
  "maxConcurrency": 2,
  "debugMode": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing every field for each scraped race

## `overview` (type: `string`):

Dataset overview with key race, location, and price fields

## `files` (type: `string`):

Bounded diagnostic artifacts created only when debug mode is enabled and a request fails

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://runsignup.com/Races"
        }
    ],
    "maxRaces": 1000,
    "startDate": "2026-09-03",
    "endDate": "1 year"
};

// Run the Actor and wait for it to finish
const run = await client.actor("hypebridge/runsignup-race-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [{ "url": "https://runsignup.com/Races" }],
    "maxRaces": 1000,
    "startDate": "2026-09-03",
    "endDate": "1 year",
}

# Run the Actor and wait for it to finish
run = client.actor("hypebridge/runsignup-race-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://runsignup.com/Races"
    }
  ],
  "maxRaces": 1000,
  "startDate": "2026-09-03",
  "endDate": "1 year"
}' |
apify call hypebridge/runsignup-race-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hypebridge/runsignup-race-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8CFqYmM8J7RKqEu4s/builds/MNyfjUofHWp70yjpO/openapi.json
