# Covers Sports Odds and Consensus Scraper (`automation-lab/covers-sports-odds-consensus-scraper`) Actor

📊 Extract Covers community betting consensus, lines, and pick counts for MLB, WNBA, and CFL. Filter sides or totals by segment and date.

- **URL**: https://apify.com/automation-lab/covers-sports-odds-consensus-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Sports
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## Covers Sports Odds and Consensus Scraper

Turn public Covers community betting sentiment into structured matchup data.

The actor extracts **consensus percentages, betting lines, and pick counts** for each side of a matchup.
Use it for daily sports-betting research, dashboards, model features, and line-versus-crowd monitoring.
No Covers login or private API key is required.

### What does Covers Sports Odds and Consensus Scraper do?

It reads public consensus tables on Covers and creates one clean dataset row per matchup.
Each row keeps the away and home values together so comparisons require no post-processing.

- 🏆 MLB, WNBA, CFL, or all available leagues
- 📈 Sides and totals consensus markets
- 👥 Overall, Team Money Leaders, and Top 10% segments
- 📊 Percentages, current line/price, and public pick counts
- 🔗 Stable team IDs and matchup detail links
- 🕒 Source and extraction timestamps for monitoring

### Who is it for?

**Betting analysts** can compare public positioning with model probabilities.

**Odds dashboards** can refresh consensus panels on a schedule.

**Data scientists** can collect sentiment features alongside prices and outcomes.

**Publishers** can monitor which games draw unusually one-sided interest.

**Automation teams** can send changing consensus records to a database or alert workflow.

### Why use this actor?

Manual copying is slow and makes side ordering easy to mix up.
The actor preserves away/home order and labels every record with its market and segment.

- Repeatable JSON, CSV, Excel, XML, and RSS exports
- Typed numeric percentages and pick counts
- No browser automation overhead
- Configurable result limit for inexpensive tests
- Ready for Apify schedules, webhooks, API clients, and MCP

### What Covers data can you extract?

| Field | Meaning |
|---|---|
| `league` | League shown by Covers |
| `market` | `sides` or `totals` |
| `segment` | Audience segment used for consensus |
| `matchupDateTime` | Covers display date and Eastern time |
| `awayTeam`, `homeTeam` | Full team names |
| `awayTeamId`, `homeTeamId` | Stable Covers team identifiers |
| `awayConsensusPercent`, `homeConsensusPercent` | Public consensus shares |
| `awayLine`, `homeLine` | Displayed side or total values |
| `awayPickCount`, `homePickCount` | Public pick volumes |
| `detailUrl` | Covers matchup consensus page |
| `sourceUrl` | Exact table requested |
| `scrapedAt` | UTC extraction timestamp |

### How to scrape Covers consensus

1. Open the actor input page.
2. Choose one league or keep **All leagues**.
3. Select **Sides** or **Totals**.
4. Choose the consensus audience segment.
5. Optionally enter a date in `YYYY-MM-DD` format.
6. Set the maximum number of matchups.
7. Click **Start**.
8. Open the Dataset tab to preview or export results.

### Input

```json
{
  "league": "all",
  "market": "sides",
  "segment": "overall",
  "maxItems": 50
}
```

| Input | Type | Default | Notes |
|---|---|---:|---|
| `league` | string | `all` | `all`, `mlb`, `wnba`, or `cfl` |
| `market` | string | `sides` | `sides` or `totals` |
| `segment` | string | `overall` | `overall`, `expert`, or `top10pct` |
| `date` | string | current | Optional `YYYY-MM-DD` competition date |
| `maxItems` | integer | 50 | Between 1 and 1,000 |

A small prefill keeps the first run cheap.
For scheduled collection, leave `date` empty to request the current board.

### Output example

```json
{
  "league": "MLB",
  "market": "sides",
  "segment": "overall",
  "matchupDateTime": "Thu. Jul 23 5:15 pm ET",
  "awayTeam": "Arizona",
  "awayTeamId": "afc3194f-5cf7-459b-9113-a3230107902e",
  "awayConsensusPercent": 31,
  "awayLine": "-131",
  "awayPickCount": 257,
  "homeTeam": "St. Louis",
  "homeTeamId": "420114c4-e4c3-40e0-aaff-a32301078454",
  "homeConsensusPercent": 69,
  "homeLine": "+114",
  "homePickCount": 571,
  "detailUrl": "https://contests.covers.com/consensus/matchupconsensusdetails/...",
  "scrapedAt": "2026-07-13T00:00:00.000Z"
}
```

### Sides and totals

Choose `sides` to collect the two team-side values displayed by Covers.
Choose `totals` to collect over/under consensus from the corresponding public table.
The output shape remains stable, and `market` records which interpretation applies.

Do not combine snapshots from different markets without grouping by `market`.
That field prevents accidental comparisons between moneyline/side and total values.

### Consensus audience segments

`overall` represents the broad Covers community table.

`expert` maps to Covers' **Team Money Leaders** selection.

`top10pct` maps to Covers' **Top 10%** segment.

Save `segment` in downstream database keys because percentages can differ for the same game.

### How much does it cost to scrape Covers sports odds consensus?

Pricing is pay per event:

- A **$0.005** one-time Actor start charge
- **$0.00010812 per matchup on BRONZE**, with plan-based tier prices from $0.00012434 (FREE) down to $0.000030274 (DIAMOND)
- Automatic volume discounts on higher Apify plans

You can control spend with `maxItems`.
The Console shows an estimate before the run and exact charged events afterward.
There are no hidden Covers subscription fees for this public scope.

### Scheduling a consensus monitor

Use an Apify schedule for daily or intraday snapshots.
Keep `date` empty so each scheduled run requests the current Covers board.

Recommended pipeline:

1. Run every hour during active game windows.
2. Export records to a database keyed by team IDs, market, segment, and start time.
3. Compare the newest percentages with the previous snapshot.
4. Alert only when the change exceeds your threshold.
5. Retain pick-count changes to distinguish movement from low-volume noise.

### Integrations

Connect the actor with:

- **Google Sheets** for a shared betting-research workbook
- **Make** for no-code percentage-change alerts
- **Zapier** for notifications and routing
- **Slack** for one-sided consensus alerts
- **Webhooks** for immediate dataset processing
- **BigQuery or Snowflake** for historical model features
- **Python notebooks** for consensus-versus-result analysis

Apify datasets can also be downloaded directly in CSV, JSON, Excel, XML, or RSS.

### API usage with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/covers-sports-odds-consensus-scraper').call({
  league: 'mlb',
  market: 'sides',
  segment: 'overall',
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### API usage with Python

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')
run = client.actor('automation-lab/covers-sports-odds-consensus-scraper').call(run_input={
    'league': 'all',
    'market': 'totals',
    'segment': 'top10pct',
    'maxItems': 100,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### API usage with cURL

```bash
curl -X POST \
  'https://api.apify.com/v2/acts/automation-lab~covers-sports-odds-consensus-scraper/runs?token=YOUR_APIFY_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"league":"wnba","market":"sides","segment":"overall","maxItems":50}'
```

Read the returned run's dataset after it finishes.
Use a secret manager rather than embedding production tokens in source code.

### Use with Apify MCP

Connect through `https://mcp.apify.com?tools=automation-lab/covers-sports-odds-consensus-scraper`.

#### Claude Code

Register the remote HTTP server from your terminal:

```bash
claude mcp add --transport http apify-covers \
  'https://mcp.apify.com?tools=automation-lab/covers-sports-odds-consensus-scraper'
```

Run `claude mcp list` to confirm the server is registered, then complete the Apify authentication prompt when Claude first connects.

#### Claude Desktop, Cursor, and VS Code

Add this server to the client's MCP JSON configuration (Claude Desktop's `claude_desktop_config.json`, Cursor's MCP settings, or VS Code's MCP configuration):

```json
{
  "mcpServers": {
    "apify-covers": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/covers-sports-odds-consensus-scraper"
    }
  }
}
```

Restart or reload the client, enable `apify-covers`, and complete the Apify authentication flow. The same endpoint and configuration work in all three clients; never paste an Apify token directly into a shared configuration file.

Example prompts:

- “Get today's overall MLB sides consensus from Covers.”
- “Extract top-10-percent totals consensus and highlight games above 65%.”
- “Compare this Covers snapshot with yesterday's records.”

### Data quality tips

- Compare team IDs instead of abbreviations when joining snapshots.
- Keep the `market` and `segment` fields in every database key.
- Treat `matchupDateTime` as Covers display text in Eastern time.
- Use `scrapedAt` as the authoritative snapshot time.
- Check pick counts before treating a large percentage as high confidence.
- Store raw line strings because formatting differs by market.
- Expect available leagues and matchups to vary by sports season.

### Error handling and troubleshooting

The actor retries temporary network failures with bounded backoff.
A non-success HTTP response fails clearly rather than returning misleading empty data.
Markup changes also produce a clear parser error instead of silent success.

**Why did I get “No consensus matchups found”?**
The selected league or date may have no public games. Try `league: "all"` and omit `date`.

**Why are there fewer rows than `maxItems`?**
`maxItems` is a cap, not a guarantee. Covers may expose fewer matchups for that filter.

**Why do percentages differ between runs?**
Consensus changes as new public picks arrive. That is expected and useful for monitoring.

### Responsible use and legality

This actor accesses public Covers pages without bypassing login controls.
Scraping legality depends on jurisdiction, purpose, and how data is stored or republished.
Review Covers' terms, applicable laws, and your compliance obligations.

The output is informational and is not betting advice.
Do not use the actor to facilitate prohibited gambling activity.
Respect reasonable run frequency and avoid unnecessary load on the source website.

### Limitations

The actor extracts the verified public consensus table, not every sportsbook's full odds feed.
Available leagues depend on the live Covers navigation and sports calendar.
Displayed dates use Covers formatting and Eastern-time labels.
Historical date availability is controlled by Covers.
A source markup redesign may require an actor update.

### Related sports scrapers

Explore other sports data tools from [automation-lab](https://apify.com/automation-lab):

- [Action Network sports odds and line movement scraper](https://apify.com/automation-lab/action-network-sports-odds-line-movement-scraper)
- Browse the [automation-lab Store profile](https://apify.com/automation-lab) for complementary sports actors.

Choose the Action Network actor for that source's line-movement workflow.
Choose this actor when Covers community consensus and public pick counts are the required signal.

### FAQ

**Does it require a Covers account?**
No. The supported consensus tables are public.

**Can I export to CSV or Excel?**
Yes. Open the dataset and select the required format.

**Can it run on a schedule?**
Yes. Apify schedules support daily and intraday monitoring.

**Does `maxItems` create more matchups?**
No. It only limits how many available rows are saved.

**Can I scrape multiple markets in one run?**
Each run selects one market. Use two scheduled tasks when you need both sides and totals.

**Is the data live?**
It reflects the public Covers table at the time shown by `scrapedAt`.

### Support

If a run fails, include the run URL and non-sensitive input in your report.
That gives maintainers the response status, selected filters, and parser logs needed to investigate.

For reproducible monitoring, keep your input configuration stable and record actor build versions with snapshots.

# Actor input Schema

## `league` (type: `string`):

League shown in Covers consensus tables.

## `market` (type: `string`):

Extract side consensus or game-total consensus.

## `segment` (type: `string`):

Covers audience segment used to calculate consensus.

## `date` (type: `string`):

Optional Covers competition date in YYYY-MM-DD format. Leave empty for the current board.

## `maxItems` (type: `integer`):

Maximum matchup rows saved to the dataset.

## Actor input object example

```json
{
  "league": "all",
  "market": "sides",
  "segment": "overall",
  "maxItems": 10
}
```

# Actor output Schema

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

No description

# 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 = {
    "league": "all",
    "market": "sides",
    "segment": "overall",
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/covers-sports-odds-consensus-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 = {
    "league": "all",
    "market": "sides",
    "segment": "overall",
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/covers-sports-odds-consensus-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 '{
  "league": "all",
  "market": "sides",
  "segment": "overall",
  "maxItems": 10
}' |
apify call automation-lab/covers-sports-odds-consensus-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/covers-sports-odds-consensus-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/nFvou84dT4hV9wb81/builds/cSRbq0w9t6sX3CNxv/openapi.json
