# How to Download Audio in MP3 Format with ReClip: A Complete Guide

> Learn how to download audio in MP3 format with ReClip. This guide shows you how to use yt-dlp flags via the Flask backend for easy MP3 downloads.

- Repository: [Avery Gan/reclip](https://github.com/averygan/reclip)
- Tags: how-to-guide
- Published: 2026-09-05

---

**ReClip downloads MP3 audio by invoking `yt-dlp` with the `-x --audio-format mp3` flags through its Flask backend when users select the MP3 pill in the web interface.**

ReClip is an open-source media downloader by `averygan/reclip` that combines a lightweight Flask backend with the `yt-dlp` library to extract and convert video streams. The application supports direct MP3 conversion by leveraging `ffmpeg` for audio re-encoding, enabling users to save audio tracks without manual post-processing. Understanding the exact flow from UI selection to file delivery allows developers to customize extraction settings or troubleshoot dependency issues.

## How ReClip Handles MP3 Conversion

The MP3 workflow relies on a three-tier architecture: the frontend sends a format preference to the Flask API, the backend constructs a `yt-dlp` command with audio-specific flags, and `ffmpeg` handles the actual transcoding. When the user selects **MP3** in the interface, the `currentFormat` variable updates to `"audio"` via the button’s `data-format="audio"` attribute located in [`templates/index.html`](https://github.com/averygan/reclip/blob/main/templates/index.html) at lines 95-97. This value persists through the API call to trigger the audio extraction path in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py).

## Step-by-Step MP3 Download Flow

### 1. Select MP3 Format in the UI

The user clicks the MP3 pill button, which toggles the active state and sets the global `format` variable. This interaction updates `currentFormat` to `"audio"` (as opposed to video formats), signaling the backend to extract rather than merge streams.

### 2. Fetch Video Metadata

The client sends a request to `/api/info` to retrieve the video title, thumbnail, and available stream formats. This step validates the URL and populates the download card before the user commits to the extraction.

### 3. Trigger the Download Request

Upon clicking **Download**, the frontend POSTs to `/api/download` (lines 66-84 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py)) with a JSON payload including the target URL and `format: "audio"`. The backend generates a unique `job_id` (UUID) to track the asynchronous operation.

### 4. Backend Audio Extraction

The `run_download` function in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) (lines 38-40) constructs the `yt-dlp` command. For MP3 requests, it appends the `-x` (extract audio) and `--audio-format mp3` flags, then executes via `subprocess.run`. This command requires `ffmpeg` to be installed on the host system to handle the codec conversion.

### 5. Poll for Job Completion

The client polls `/api/status/<job_id>` (lines 87-95) until the job dictionary reports `"status": "done"`. During this phase, the backend monitors the subprocess output and updates the job state accordingly.

### 6. Retrieve the MP3 File

Once processing completes, the browser requests `/api/file/<job_id>` (lines 99-104), which streams the generated MP3 file from the `DOWNLOAD_DIR` using Flask’s `send_file` method.

## Required Dependencies

Because ReClip delegates encoding to external tools, the host must have `ffmpeg` installed and available in the system PATH. Without it, the `--audio-format mp3` flag will fail silently or raise a conversion error. Install via your package manager (e.g., `brew install ffmpeg` on macOS or `apt install ffmpeg` on Ubuntu) before starting the application.

## Code Implementation Details

### Frontend: Selecting MP3 and Initiating Download

The JavaScript handles format selection and initiates the POST request to the download endpoint:

```javascript
// Switch to MP3 mode
function setFormat(btn) {
  document.querySelectorAll('.pill').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  currentFormat = btn.dataset.format;   // "audio" for MP3
}

// Trigger download for a single card
async function dlCard(idx) {
  const c = cardData[idx];
  c.status = 'downloading';
  renderCard(idx);
  const res = await fetch('/api/download', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      url: c.url,
      format: currentFormat,          // "audio"
      format_id: c.selectedFormatId,
      title: c.title || '',
    }),
  });
  const data = await res.json();
  // …polling logic follows…
}

```

### Backend: Building the yt-dlp Command

The `run_download` function dynamically constructs the command array based on the `format_choice` parameter:

```python
def run_download(job_id, url, format_choice, format_id):
    out_template = os.path.join(DOWNLOAD_DIR, f"{job_id}.%(ext)s")
    cmd = ["yt-dlp", "--no-playlist", "-o", out_template]

    if format_choice == "audio":                     # <-- MP3 path

        cmd += ["-x", "--audio-format", "mp3"]
    elif format_id:
        cmd += ["-f", f"{format_id}+bestaudio/best", "--merge-output-format", "mp4"]
    else:
        cmd += ["-f", "bestvideo+bestaudio/best", "--merge-output-format", "mp4"]
    cmd.append(url)
    # Run yt‑dlp and handle results …

```

### Polling for Completion

The status endpoint returns the current state of the background job:

```python
@app.route("/api/status/<job_id>")
def check_status(job_id):
    job = jobs.get(job_id)
    if not job:
        return jsonify({"error": "Job not found"}), 404
    return jsonify({
        "status": job["status"],
        "error": job.get("error"),
        "filename": job.get("filename"),
    })

```

## Summary

- **Format Selection**: The UI sets `currentFormat` to `"audio"` via `data-format="audio"` in [`templates/index.html`](https://github.com/averygan/reclip/blob/main/templates/index.html).
- **API Endpoint**: `POST /api/download` receives the request and spawns a background job identified by a UUID.
- **Audio Extraction**: [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) constructs a `yt-dlp` command with `-x --audio-format mp3` to extract and convert streams.
- **Dependency**: `ffmpeg` must be installed on the server to handle MP3 encoding.
- **Delivery**: The client polls `/api/status/<job_id>` and retrieves the final file from `/api/file/<job_id>`.

## Frequently Asked Questions

### What dependencies are required for MP3 conversion?

ReClip requires `ffmpeg` to be installed on the host system. The backend invokes `yt-dlp` with the `--audio-format mp3` flag, which shells out to `ffmpeg` for the actual audio transcoding. Without this dependency, the extraction process will fail.

### How does ReClip convert video to MP3?

According to the source code in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py), the backend checks if `format_choice == "audio"` and appends the `-x` (extract audio) and `--audio-format mp3` flags to the `yt-dlp` command. This extracts the best audio stream and re-encodes it into MP3 format using `ffmpeg`.

### How does the frontend communicate the MP3 format choice?

The frontend stores the selection in a global `currentFormat` variable when the user clicks the MP3 pill button defined in [`templates/index.html`](https://github.com/averygan/reclip/blob/main/templates/index.html) at lines 95-97. This value is passed as the `format` property in the JSON body of the `POST` request to `/api/download`.

### Where are downloaded MP3 files stored temporarily?

Files are written to the `DOWNLOAD_DIR` directory using a filename template of `{job_id}.%(ext)s`. The `job_id` is a UUID generated at the start of the request, ensuring unique filenames for concurrent downloads.