EPG Feed Guide
This page explains how to fetch our electronic programme guide (EPG) and how to read the data. The feed is available as XMLTV, JSON and iCalendar and always contains the latest approved schedule.
01Overview
For EPG systems
The common exchange format for set-top boxes, middleware and IPTV platforms. Validates against the official xmltv.dtd.
For websites & apps
The same programme data with a few extras: channel languages, contact, DVB content code.
For calendars
Subscribe in Outlook, Google Calendar or Apple Calendar to see the schedule as events.
- Read-only: the feed cannot change anything.
- Always current: every request is built live from the approved schedule. Changes still awaiting internal approval are never published.
- Local time: all times are local channel time (
Europe/Zurich) with the UTC offset included, so summer and winter time are handled correctly. - UTF-8: all text is UTF-8, without HTML tags or invisible control characters.
02Your feed link
You will normally receive a personal link containing an access token. The token identifies you; please keep it confidential. If it is ever compromised, we can revoke it and send you a new one.
| Format | Short link | Long form (works on every server) |
|---|---|---|
| XMLTV | <token>.xml | ?t=<token>&f=xml |
| JSON | <token>.json | ?t=<token>&f=json |
| ICS | <token>.ics | ?t=<token>&f=ics |
Both forms return exactly the same data. Use whichever form you were given.
epg.xml, epg.json and epg.ics.03Choosing the time range
Without parameters you receive the default range set by the channel (for example yesterday plus the next 7 days). Add a query string to request a specific period:
| Parameter | Example | Returns |
|---|---|---|
| date | ?date=2026-10-20 | One day, 00:00 to 24:00 local time. |
| from, to | ?from=2026-10-20&to=2026-10-26 | Several days, both days included. Maximum 31 days. |
| past, future | ?past=0&future=14 | Days back (0–31) and days ahead (1–31), counted from today. |
Dates are always written YYYY-MM-DD. Parameters can be added to both link forms:
<token>.xml?date=2026-10-20
?t=<token>&f=json&from=2026-10-20&to=2026-10-26
04XMLTV
One <channel> followed by the programmes in chronological order. Standard XMLTV according to the official xmltv.dtd, in DTD element order. Elements without a value are omitted (no empty tags), so receivers such as TVHeadend, Jellyfin, Plex or Enigma2 read the feed without workarounds. Only <title> and the ciegolink ID are always present.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv generator-info-name="CiegoLink EPG Planer" generator-info-url="https://ciegolink.com" source-info-name="Example TV" source-info-url="https://example.tv">
<channel id="example.tv">
<display-name lang="de">Example TV</display-name>
<icon src="https://…/uploads/logo-1a2b3c4d.png"/>
<url>https://example.tv</url>
</channel>
<programme start="20261020201500 +0200" stop="20261020214500 +0200" channel="example.tv">
<title lang="de">Tatort</title>
<sub-title lang="de">Der Fall Müller</sub-title>
<desc lang="de">Kommissarin Weber ermittelt …</desc>
<category lang="en">Movie / Drama</category> <!-- 1st: DVB genre -->
<category lang="de">Krimi</category> <!-- 2nd: channel category -->
<length units="minutes">90</length>
<icon src="https://…/uploads/20261018-154401-704fcde2.jpg"/>
<episode-num system="xmltv_ns">11.4.</episode-num>
<episode-num system="onscreen">S12E05</episode-num>
<episode-num system="ciegolink">t044473196da4-202610202015</episode-num>
</programme>
</tv>
start/stop:YYYYMMDDhhmmss ±hhmmin local time with offset.- Language:
lang(two-letter code of the channel's main language, e.g.de) on<display-name>,<title>,<sub-title>,<desc>and the channel category. The DVB genre is always the official English term withlang="en". The full list of channel languages is in the JSON feed. <category>: first the DVB genre, then the channel's own category – each only if set.<episode-num>:xmltv_nsandonscreenonly if season or episode is known;ciegolink(unique broadcast ID) is always present. Receivers ignore unknown systems.<rating system="explicit"><value>yes</value></rating>appears only for explicit content (adults only). XMLTV has no dedicated explicit flag; this is the usual way to carry it.
05JSON
The same data as XMLTV plus channel languages and contact details. Every field is always present: empty texts are "", missing numbers are null.
{
"generator": "CiegoLink EPG Planer",
"generated": "2026-10-18T18:40:00+02:00",
"timezone": "Europe/Zurich",
"from": "2026-10-20T00:00:00+02:00",
"to": "2026-10-21T00:00:00+02:00",
"channel": {
"id": "example.tv",
"name": "Example TV",
"language": "de-CH",
"languages": ["de-CH", "fr-CH"],
"logo": "https://…/uploads/logo-1a2b3c4d.png",
"url": "https://example.tv",
"contact": { "phone": "+41 44 123 45 67", "email": "epg@example.tv" }
},
"programmes": [
{
"id": "t044473196da4-202610202015",
"show_id": "s29aaffabc8b7",
"start": "2026-10-20T20:15:00+02:00",
"stop": "2026-10-20T21:45:00+02:00",
"duration": 90,
"title": "Tatort",
"subtitle": "Der Fall Müller",
"description": "Kommissarin Weber ermittelt …",
"season": 12,
"episode": 5,
"episode_label": "S12E05",
"genre": "film",
"genre_name": "Movie / Drama",
"dvb_content": "0x1",
"category": "Krimi",
"image": "https://…/uploads/20261018-154401-704fcde2.jpg",
"explicit": false
}
]
}
06iCalendar (ICS)
Paste the .ics link into your calendar app as a subscription (not an import), so it updates automatically.
- One event per broadcast.
SUMMARYis the title. DESCRIPTIONcontains season/episode, subtitle and description.CATEGORIEScontains the genre and category,IMAGEthe programme image.UIDis the programme ID (see Programme IDs), so calendar apps update events instead of duplicating them.
07Field reference
| JSON | XMLTV | Content |
|---|---|---|
| id | episode-num system="ciegolink" | Unique ID of the broadcast. See Programme IDs. |
| show_id | – | ID of the show (series). The same for all broadcasts of a show. |
| start, stop | start, stop | Start and end in local time with UTC offset (not Unix timestamps). XMLTV: 20261020201500 +0200 · JSON: ISO 8601 2026-10-20T20:15:00+02:00 |
| duration | length | Duration in minutes. |
| title | title | Name of the show. |
| subtitle | sub-title | Second title line, typically the episode title. Not closed captions. |
| description | desc | Synopsis. Plain text and may contain line breaks. |
| season, episode | episode-num | Season and episode number, starting at 1. null if not set. |
| episode_label | episode-num system="onscreen" | Display form, e.g. S12E05, S12 or E05. |
| genre | – | Genre key, e.g. film (see table below). |
| genre_name | 1st category | Official English DVB genre name. |
| dvb_content | – | DVB content nibble level 1, e.g. 0x1. |
| category | 2nd category | The channel's own category, free text. |
| explicit | rating system="explicit" | Explicit content, adults only. JSON true / false, XMLTV only present (yes) when true. Set per show. |
| image | icon src | Programme image. Uploaded images are always 1920×1080 JPEG. |
Genres (DVB)
The genre follows the content descriptor of ETSI EN 300 468 (content_nibble_level_1), so it can be mapped directly into DVB EIT.
| genre | dvb_content | genre_name |
|---|---|---|
| film | 0x1 | Movie / Drama |
| news | 0x2 | News / Current affairs |
| show | 0x3 | Show / Game show |
| sports | 0x4 | Sports |
| kids | 0x5 | Children's / Youth programmes |
| music | 0x6 | Music / Ballet / Dance |
| arts | 0x7 | Arts / Culture |
| social | 0x8 | Social / Political issues / Economics |
| education | 0x9 | Education / Science / Factual topics |
| leisure | 0xA | Leisure hobbies |
| special | 0xB | Special characteristics |
Season & episode
xmltv_ns counts from zero and has the form season.episode.part; unknown parts stay empty.
| Season / episode | xmltv_ns | onscreen |
|---|---|---|
| 12 / 5 | 11.4. | S12E05 |
| 12 / – | 11.. | S12 |
| – / 5 | .4. | E05 |
| – / – | both omitted | |
Programme IDs
Each broadcast has an ID of the form <series-id>-<YYYYMMDDhhmm>. The time part is the broadcast's originally planned slot.
- The ID stays the same when a single broadcast is edited or moved.
- The ID changes when a whole recurring series is moved to a new time.
08HTTP, caching & errors
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | The feed in the requested format. |
| 400 | Invalid parameter, e.g. wrong date format, range over 31 days or unknown format | JSON: {"error": "…"} |
| 403 | Token missing, wrong or revoked | Plain text: Zugriff verweigert (access denied) |
| 404 | Short link not available on this server – use the long form | Server page |
- Caching: responses may be cached for 60 seconds (
Cache-Control: public, max-age=60). - Polling: fetching every 15 to 60 minutes is plenty. Please do not poll more than once per minute.
- CORS: enabled (
Access-Control-Allow-Origin: *), so the JSON feed can be loaded directly from a web page. - Content types:
application/xml,application/jsonandtext/calendar, all UTF-8.
09Integration checklist
- Store your link with the token securely, e.g. as a secret in your configuration rather than in public code.
- Map our channel ID (
<channel id="…">) to your channel. It only changes after prior notice. - Fetch the default range every 15–60 minutes, or request specific days with
?date=or?from=…&to=…. - Replace all programmes of the fetched range with the response.
- Use the first
<category>, ordvb_contentin JSON, for genre mapping to DVB EIT. - Show
sub-titleand theonscreenepisode number where your EPG has room for them.
channel.contact.