# How to Add a New Channel to the Free-TV/IPTV Playlist

> Quickly add a new channel to your Free-TV/IPTV playlist by editing the country-specific Markdown file and committing changes. Learn the simple process now.

- Repository: [Free TV/IPTV](https://github.com/Free-TV/IPTV)
- Tags: how-to-guide
- Published: 2026-06-26

---

**To add a new channel to the Free-TV/IPTV playlist, edit the appropriate country-specific Markdown file in the `lists/` directory to include a table row with the `[>]` stream marker, then commit your changes to trigger the automatic `playlist.m3u8` generation.**

Free-TV/IPTV is a community-driven repository that aggregates free, legal streaming television channels into a single **M3U8** playlist. Unlike traditional IPTV management systems that require database access or complex configuration files, this project uses a declarative Markdown-based workflow where contributors simply edit human-readable table files. Adding a new channel requires modifying the appropriate country list in the `lists/` directory to specify the stream URL, channel metadata, and verification status.

## Understanding the Playlist Architecture

The repository generates its master `playlist.m3u8` file automatically using the [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) script. This Python parser scans every `.md` file in the `lists/` directory, extracting only the table rows whose **Link** column begins with the special marker `[>]`. Rows containing `[x]` or other prefixes are ignored, ensuring only verified, working streams appear in the final output.

### How make_playlist.py Processes Channel Data

According to the Free-TV/IPTV source code, the generator enforces a strict separation between data and presentation. Channel metadata lives in plain Markdown tables, while [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) handles the compilation logic. When executed, the script reads each country file, validates the `[>]` prefix denotes an active stream, and concatenates the entries into the standard M3U8 format. This design ensures that editing the `.md` files remains safe and deterministic, with no risk of corrupting the playlist structure.

### Required Table Format

Each channel entry must follow a specific five-column table structure:

| Column | Format Requirements |
|--------|---------------------|
| **#** | Numeric identifier (sequential or unique) |
| **Channel** | Human-readable name with optional quality indicators |
| **Link** | Must start with `[>]` followed by the stream URL in parentheses |
| **Logo** | HTML `<img>` tag with `height="20"` pointing to a public image host |
| **EPG id** | Optional string identifier for electronic program guide data |

The **Link** column is the critical filter: only URLs prefixed with `[>]` are included in `playlist.m3u8`, while `[x]` marks invalid or offline streams.

## Step-by-Step Guide to Adding Channels

Follow this workflow to contribute new channels to the repository.

### Locate the Correct Country List

Navigate to the `lists/` directory and identify the appropriate Markdown file for your channel's country of origin. For example, U.S. channels belong in [`lists/usa.md`](https://github.com/Free-TV/IPTV/blob/main/lists/usa.md), while German channels reside in [`lists/germany.md`](https://github.com/Free-TV/IPTV/blob/main/lists/germany.md). If the country file does not exist, you will need to create one following the structure outlined below.

### Format Your Channel Entry

Insert a new table row following the pipe-delimited syntax. Below is the exact format required for the [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) parser:

```markdown
| #   | Channel            | Link                         | Logo                                           | EPG id |

|:---:|:------------------:|:----------------------------:|:----------------------------------------------:|:------:|
| 43  | Example TV Ⓢ      | [>](https://example.com/stream.m3u8) | <img height="20" src="https://i.imgur.com/xyz.png"/> | ExampleTV.us |

```

Key formatting details:

- **Channel symbols**: Append `Ⓢ` for standard-definition (non-HD) streams, `Ⓖ` for geo-blocked content, or `Ⓨ` for YouTube Live streams.
- **Logo hosting**: Use publicly accessible image URLs (Imgur is commonly used by maintainers).
- **Placement**: Insert the row under the appropriate technology heading (e.g., **ATSC**, **DVB-S**, **Pluto**) within the file.

### Submit Your Changes

Commit your modified `.md` file and open a Pull Request. The repository's CI system automatically executes [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) upon merge, regenerating `playlist.m3u8` to include your new channel. Because the generator never modifies source Markdown files, your changes remain declarative and reversible.

## Creating a New Country List

To add channels from a country not currently represented, create a new file named `lists/[country].md` with this boilerplate:

```markdown
<h1>Country Name</h1>

<h2>ATSC</h2>

| #   | Channel | Link                         | Logo                                           | EPG id |

|:---:|:-------:|:----------------------------:|:----------------------------------------------:|:------:|
| 1   | New Channel | [>](https://stream.url.com/live.m3u8) | <img height="20" src="https://i.imgur.com/logo.png"/> | NewChannel.cc |

```

After creating the file, add a reference to it in the repository's [`README.md`](https://github.com/Free-TV/IPTV/blob/main/README.md) under the "Free TV" table so users can discover the new list.

## Testing Changes Locally

Before submitting a Pull Request, validate your additions by running the generator locally:

```bash
python make_playlist.py

```

This command parses all `.md` files in `lists/` and outputs a fresh `playlist.m3u8`. Verify that your new channel appears in the generated file and that the stream URLs are correctly formatted.

## Summary

- Free-TV/IPTV uses **declarative Markdown files** in `lists/` to define channels rather than databases or configuration files.
- The [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) script only includes table rows where the **Link** column starts with `[>]`, ignoring entries marked with `[x]`.
- Required fields include a numeric ID, channel name (with optional symbols like `Ⓢ` or `Ⓖ`), a `[>]` prefixed URL, and a logo image tag.
- Changes are submitted via Pull Request, triggering automatic regeneration of `playlist.m3u8` through the CI pipeline.
- Test modifications locally by executing `python make_playlist.py` to verify the generated output.

## Frequently Asked Questions

### What does the `[>]` symbol mean in the Link column?

The `[>]` prefix serves as a validation marker that tells [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) to include this row in the final `playlist.m3u8`. According to the Free-TV/IPTV source code, this distinguishes active, verified streams from invalid or offline entries marked with `[x]`. Only rows containing this specific marker are concatenated into the master playlist.

### Can I use any image hosting service for the channel logo?

While the parser accepts any valid URL in the Logo column's `<img>` tag, the project recommends using Imgur or other reliable public hosts. The logo must be accessible via HTTPS and should use the exact HTML format: `<img height="20" src="..."/>`. Private or temporary image hosts may result in broken icons for end users.

### How do I indicate that a channel is geo-blocked or standard definition?

Append specific Unicode symbols to the channel name in the **Channel** column. Use `Ⓢ` (circled S) to indicate standard-definition streams that are not HD, `Ⓖ` (circled G) for geo-blocked content requiring specific regional access, or `Ⓨ` (circled Y) for YouTube Live streams. These markers help users identify stream characteristics before playback.

### Do I need to manually update the playlist.m3u8 file?

No. The `playlist.m3u8` file is generated automatically by the CI system when your Pull Request is merged. Running `python make_playlist.py` locally is only necessary for testing. Never manually edit the `playlist.m3u8` file directly, as the generator will overwrite it with the compiled output from the Markdown source files.