# Live Football Scores: Bundesliga, Champions League & More (`m_ctim/live-football-scores`) Actor

Live and final scores, goal scorers and half-time results for the Bundesliga, Champions League, Europa League, DFB-Pokal, Premier League, LaLiga and German ice hockey. Open data from OpenLigaDB (ODbL), with a monitor mode for goal alerts.

- **URL**: https://apify.com/m\_ctim/live-football-scores.md
- **Developed by:** [Timothy Kelvin](https://apify.com/m_ctim) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Live Football Scores: Bundesliga, Champions League & More

Live and final scores, goal-by-goal timelines and half-time results for German and European football, plus German ice hockey. Run it on demand for a scoreboard, or schedule it in monitor mode to get only the matches where something just happened: a goal, kickoff, or full time.

| Competition | Status |
|---|---|
| 1. Bundesliga, 2. Bundesliga, 3. Liga, DFB-Pokal, Frauen-Bundesliga | Complete and current |
| UEFA Champions League, UEFA Europa League | Complete and current |
| DEL (German ice hockey), Champions Hockey League | Complete and current |
| Premier League, LaLiga | Community-maintained: recent results are often entered days late |

The data comes from [OpenLigaDB](https://www.openligadb.de), a community-run open sports database that publishes its data under the Open Database License. It is read over a documented public API: no scraping, no proxies, no login.

### Here's a real match it returns

```json
{
  "matchId": 87388,
  "league": "ucl",
  "leagueName": "Champions League 2026/2027",
  "sport": "football",
  "round": "1.Spieltag",
  "kickoffUtc": "2026-09-08T16:45:00.000Z",
  "status": "finished",
  "minutesSinceKickoff": null,
  "homeTeam": "FC Brügge",
  "homeTeamShort": "Brügge",
  "awayTeam": "Aston Villa",
  "awayTeamShort": "Villa",
  "homeScore": 2,
  "awayScore": 3,
  "halfTimeHomeScore": 1,
  "halfTimeAwayScore": 3,
  "periodScores": [
    { "period": "Half-time", "home": 1, "away": 3 },
    { "period": "Full-time", "home": 2, "away": 3 }
  ],
  "goals": [
    { "minute": 11, "scorer": "John McGinn", "team": "away", "homeScore": 0, "awayScore": 1, "isPenalty": false, "isOwnGoal": false, "isOvertime": false },
    { "minute": 19, "scorer": "Hugo Vetlesen", "team": "home", "homeScore": 1, "awayScore": 1, "isPenalty": false, "isOwnGoal": false, "isOvertime": false },
    { "minute": 22, "scorer": "Emiliano Buendía", "team": "away", "homeScore": 1, "awayScore": 2, "isPenalty": false, "isOwnGoal": false, "isOvertime": false }
  ],
  "dataCompleteness": "complete",
  "source": "Data from OpenLigaDB (www.openligadb.de), licensed under ODbL 1.0"
}
```

(Goal list shortened here; the real row lists all five goals.)

### Match status

| `status` | Meaning |
|---|---|
| `scheduled` | Not started. Score is `null`. |
| `live` | Kicked off and not yet marked finished. The score follows the goal list as it's entered. |
| `finished` | Final result recorded. |
| `result_pending` | Kickoff was hours ago but no result has been entered yet. The score is `null`, never a made-up 0-0. |

`minutesSinceKickoff` is plain elapsed time for live matches. OpenLigaDB has no official match clock, so it includes half-time and stoppages.

Hockey matches report `periodScores` as Period 1, 2 and 3, plus overtime or shootout when played.

### Input

| Field | What it does |
|---|---|
| `leagues` | `bl1`, `bl2`, `bl3`, `dfb`, `ucl`, `uel`, `epl`, `laliga`, `frauen-bl`, `del`, `chl`. Default `bl1`, `bl2`, `ucl`. |
| `range` | `current_round` (default), `live`, `today`, `yesterday`, `tomorrow`, `last_7_days`, `next_7_days`, or `custom`. Dates are UTC. |
| `dateFrom`, `dateTo` | For `custom`, `YYYY-MM-DD`. |
| `statuses` | Keep only `scheduled`, `live`, `finished` and/or `result_pending`. |
| `team` | Only matches involving a team whose name contains this text, e.g. `Bayern`. |
| `mode` | `snapshot` (default) or `monitor`. |
| `monitorStoreName` | Where monitor mode keeps the previous scores. |
| `maxMatches` | Cap, earliest kickoff first. Default 500. |

Everything happening in the Bundesliga right now:

```json
{ "leagues": ["bl1"], "range": "live" }
```

Bayern Munich's results over the last week, in every competition:

```json
{ "leagues": ["bl1", "dfb", "ucl"], "range": "last_7_days", "team": "Bayern" }
```

### Monitor mode: goal alerts

Set `mode` to `monitor` with `range: "live"` or `"today"`, and schedule it during match days. Each run returns only matches whose score or status changed since the previous run:

```json
{
  "matchId": 83190,
  "status": "live",
  "homeScore": 2,
  "awayScore": 1,
  "changeType": "score_changed",
  "previousStatus": "live",
  "previousHomeScore": 1,
  "previousAwayScore": 1
}
```

(Illustrative.) `changeType` is `score_changed`, `status_changed` (kickoff, full time), or `new`. The first run saves a baseline and reports every match as `new`.

**Please schedule sensibly.** OpenLigaDB is a free, privately funded service, and its fair-use terms ask for at most one request per league every 30 to 60 seconds during live matches, and far fewer otherwise. A schedule of every minute or two on match days, and a few times a day otherwise, is plenty. The actor also spaces out its own requests and backs off if the service is busy.

### Pricing

Charged per match returned. In monitor mode only changed matches are returned, so quiet minutes cost nothing.

### Good to know

- **Community data.** Results are entered by OpenLigaDB volunteers without editorial review. Live goals can lag, and occasionally contain errors that are corrected later. Don't use this where a wrong score would cause harm.
- **German spellings.** Team and round names are as entered in OpenLigaDB, often in German: "FC Brügge", "1.Spieltag" (matchday 1).
- **No US leagues.** MLB, NBA, NFL and NHL score data is licensed commercially by the leagues, and there's no open source this actor could use for them.
- **Team logos are not included.** OpenLigaDB links to logos hosted by third parties without granting rights to them, and asks apps not to hotlink them.
- **Availability.** OpenLigaDB is run by one volunteer operator with no uptime guarantee. If a competition can't be fetched, the run carries on with the others and says which one failed.

### Data licence and attribution

Match data is from OpenLigaDB and licensed under the [Open Database License (ODbL) 1.0](https://opendatacommons.org/licenses/odbl/1-0/). Every row carries the attribution in its `source` field. If you publish the data, credit it as **"Data from OpenLigaDB (www.openligadb.de), licensed under ODbL 1.0"**. If you publicly share a modified copy of the database itself, it must stay under the ODbL; displaying scores in an app or on a page only needs the credit.

This actor is unofficial and is not affiliated with OpenLigaDB, any league, club or governing body.

# Actor input Schema

## `leagues` (type: `array`):

Which competitions to return. Premier League and LaLiga are volunteer-maintained and recent results can arrive days late; the German leagues, European cups and hockey are kept fully up to date.

## `range` (type: `string`):

"Live now" returns only matches in progress, and is empty when nothing is being played.

## `dateFrom` (type: `string`):

YYYY-MM-DD, UTC. Used when "Which matches" is Custom dates.

## `dateTo` (type: `string`):

YYYY-MM-DD, UTC, inclusive.

## `statuses` (type: `array`):

Keep only matches in these states. All by default.

## `team` (type: `string`):

Only matches involving a team whose name contains this text, e.g. "Bayern" or "Dortmund".

## `mode` (type: `string`):

Schedule monitor mode during match days to get goal and full-time alerts.

## `monitorStoreName` (type: `string`):

Key-value store that holds the previous scores. Use a different name for each separate monitor.

## `maxMatches` (type: `integer`):

Stop after this many matches, earliest kickoff first.

## Actor input object example

```json
{
  "leagues": [
    "bl1",
    "bl2",
    "ucl"
  ],
  "range": "current_round",
  "mode": "snapshot",
  "monitorStoreName": "live-football-scores-monitor",
  "maxMatches": 500
}
```

# Actor output Schema

## `results` (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 = {
    "leagues": [
        "bl1",
        "bl2",
        "ucl"
    ],
    "range": "current_round"
};

// Run the Actor and wait for it to finish
const run = await client.actor("m_ctim/live-football-scores").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 = {
    "leagues": [
        "bl1",
        "bl2",
        "ucl",
    ],
    "range": "current_round",
}

# Run the Actor and wait for it to finish
run = client.actor("m_ctim/live-football-scores").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 '{
  "leagues": [
    "bl1",
    "bl2",
    "ucl"
  ],
  "range": "current_round"
}' |
apify call m_ctim/live-football-scores --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,m_ctim/live-football-scores"
        }
    }
}
```

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/AKeeK89SdfZlLcgrX/builds/R5j960pROYtfdxGzx/openapi.json
