Skip to main content

📖 WattPDL: Wattpad Story Downloader

Save your favorite stories as .txt, .docx, .epub, .md, or .pdf files, whole or chapter by chapter, for offline reading.

Python PyPI License Platform Status Tests

English | Bahasa Indonesia

✨ About

WattPDL is a lightweight Python script that downloads the chapters of a Wattpad story of your choice and saves them as a clean, tidy plain .txt file, a Word .docx document, an .epub ebook, a Markdown .md file, or a .pdf. You can download the whole story as a single file, every chapter separately in one .zip, or only the chapters you pick, complete with the story cover automatically embedded in .docx/.epub/.pdf. No login, no API key, just the story link or ID.

"Because a good story deserves to be read anytime, even without internet."

🎯 Features

Feature Description
🎨 Neat CLI display Panels, story info tables, and colors thanks to the rich library
🌍 English and Indonesian UI The CLI is in English by default; switch with --ui-lang id (menus, messages, and --help)
🧩 4 download modes Everything in 1 file, everything separate in a .zip, pick several chapters, or just 1 chapter
📄 5 file formats Save as plain .txt, Word .docx, .epub ebook, Markdown .md, or .pdf
🖼️ Automatic cover The story cover is embedded in .docx/.epub/.pdf files (can be turned off with --no-cover)
🖼️ Inline images Optional (--include-images) download & embed of images inside chapter text, not just the cover
📚 Rich EPUB metadata Genre/tags, story description, and publish date are saved as book metadata
⏭️ Skip existing files Skip the download if the output file already exists in the target folder, so nothing is overwritten by accident
📁 Choose the save folder Defaults to the system Downloads folder, customizable
🔄 Auto-retry A failed chapter is retried up to 3 times before being skipped
📊 Animated progress bar Spinner, percentage, chapter count, and estimated time remaining
📋 Final summary A report panel listing failed chapters (if any) when finished
🗂 Safe file names Illegal characters are removed from file names automatically
🔗 Source link saved The story URL is included in the header of the resulting file
⚡ No login Uses Wattpad's public endpoint, so no account is needed
↻ Automatic resume If the process stops midway, run the same story again: chapters that already succeeded are not downloaded again
⚙️ Remembers preferences The last save folder, file format, and language are reused in the next session
🤖 Non-interactive mode Run with command line arguments for scripting/automation, no prompts to answer
⚡ Parallel download --workers N downloads several chapters at once, speeding up long stories significantly
🐢 Adaptive rate limit The delay between chapters slows down automatically when Wattpad starts limiting requests (429/503), then gradually speeds up again
👤 Download by author --user <username> downloads all or selected stories from one author at once
🔔 New chapter detection --check-updates reports which ongoing stories already have new chapters
👀 Watch mode --watch monitors 1 story continuously and re-downloads as soon as a new chapter appears
💾 Metadata cache Story info is cached briefly so repeated attempts in a short time do not always hit the API
🔔 wattpdl update check Notifies you automatically when a newer wattpdl version is on PyPI
🎯 Specific error messages Different messages for a deleted story (404) vs a private/restricted one (403)
🌐 --lang Sets the EPUB metadata language code (default id) for stories in other languages

📦 Requirements

  • Python 3.9 or newer
  • Internet connection
  • Libraries: requests, rich, python-docx, EbookLib, reportlab, installed automatically together with wattpdl, no manual install needed

Never used a terminal? Start here

🪟 How to open a terminal on Windows
  1. Press the Windows key, type PowerShell, then press Enter
  2. A black/blue window opens. That is where you type commands
  3. Every python ... or pip ... command in this guide is typed in that window, followed by Enter
🍎 How to open a terminal on macOS
  1. Press Cmd + Space, type Terminal, then press Enter
  2. Type the commands from this guide there, followed by Enter
🐧 How to open a terminal on Linux

Press Ctrl + Alt + T, or search for the "Terminal" app in your application menu.

Don't have Python yet?

  1. Go to python.org/downloads and download the latest version
  2. Windows only: during installation, tick the "Add Python to PATH" box on the first screen before clicking Install. If you miss this, the python command will not be recognized later
  3. After installing, open a terminal (see the guide above) and check with:
python --version
# or
python3 --version

If a version number appears (for example Python 3.12.1), you are ready.

🚀 Installation

Option A: Install from PyPI (easiest)

pip install wattpdl

If pip is not recognized, try:

python -m pip install wattpdl

If you get an externally-managed-environment error (usually on Linux):

pip install wattpdl --break-system-packages

Once installed, the wattpdl command works from any terminal. Continue to Usage.

Option B: Install from source (for development / to read or change the code)

1. Get the project code

I have Git installed
git clone https://github.com/nekonaru/wattpdl.git
cd wattpdl
I don't have Git
  1. Open the repository page on GitHub
  2. Click the green Code button → choose Download ZIP
  3. Extract the downloaded ZIP file to a folder of your choice
  4. In the terminal, go into the extracted folder, for example:
cd Downloads/wattpdl-main

2. Install in "editable" mode

pip install -e .

Same as Option A, add --break-system-packages at the end if you get an externally-managed-environment error.

This also registers the wattpdl command, but it loads the code directly from this folder, which is ideal if you want to modify the code and see the result right away without reinstalling.

🖥️ Usage

Run:

wattpdl

If you installed from source without pip install -e ., run it with python -m wattpdl from inside the src/ folder. The editable install above is recommended, though.

Enter the story link or ID when asked:

Wattpad story link or ID: https://www.wattpad.com/story/123456789-story-title

or just the ID:

Wattpad story link or ID: 123456789

Choose the download mode:

  1  All chapters → 1 combined file
  2  All chapters → separate file per chapter, packed as .zip
  3  Select several chapters → 1 combined file
  4  Select 1 chapter only

Select mode [1/2/3/4] (1):
  • Mode 1: the most common way, the whole story as one tidy file from the first to the last chapter
  • Mode 2: good if you want to read chapter by chapter, producing one .zip with a file per chapter
  • Mode 3: a numbered list of all chapter titles appears, then type the numbers you want, combining commas and ranges, for example: 1,3,5-8
  • Mode 4: a list of all chapter titles appears, type a single number to download only that chapter

Choose the file format:

  1  Plain text (.txt)
  2  Word document (.docx)
  3  Ebook (.epub)
  4  Markdown (.md)
  5  PDF (.pdf)

Select file format [1/2/3/4/5] (1):

Choose the save folder:

Default folder: C:\Users\user\Downloads
Press Enter to use that folder, or type another path:

Press Enter to save in Downloads, or type a custom path such as:

  • Windows: D:\Stories\Wattpad
  • Linux/macOS: /home/user/stories

Wait for it to finish:

⠋ Chapter 24...              ████████████████░░░░░░░░░░░░░░  53.3%  24/45  0:00:12  left 0:00:11

Done! 🎉

╔══════ 🎉 Success!  All chapters saved ══════╗
║ 📁 File saved to   C:\Users\user\Downloads\Story_Title.txt ║
║ ✅ Succeeded       45/45                                   ║
║ ⏱️  Total time      2m 18s                                  ║
╚═════════════════════════════════════════════╝

↻ Automatic Resume

If the download stops midway (connection lost, terminal closed, laptop shut down), every chapter that already succeeded is saved automatically in ~/.wattpdl/progress/<story_id>.json.

Run again with the same story (same ID/link), and WattPDL will:

  • Skip chapters that already succeeded (used from the cache, not fetched again)
  • Download only the chapters that have not succeeded yet or failed earlier

The progress file is deleted automatically once all chapters have been downloaded in a single session. To force a download from scratch, delete the ~/.wattpdl/progress/ folder manually.

Not the same as --skip-existing: the resume above works at the chapter level (continuing a download that stopped midway). --skip-existing works at the output file level: if the final file (for example Story_Title.epub) already exists in the target folder, the whole download is skipped entirely, which is handy together with cron/Task Scheduler so stories that were already downloaded are not downloaded again.

⚙️ Saved Preferences

The last save folder, file format, and display language you chose are saved automatically in ~/.wattpdl/config.json and reused as defaults in the next session, so there is no need to fill them in every time you run the script.

🌍 Display Language

The CLI display (menus, prompts, error messages, and --help text) is available in English (default) and Indonesian.

wattpdl --ui-lang id              # Indonesian, this choice is remembered for next runs
wattpdl --ui-lang en              # back to English
WATTPDL_LANG=id wattpdl           # via environment variable

Priority order: --ui-lang → env WATTPDL_LANG → ui_lang in ~/.wattpdl/config.json → default en.

--ui-lang only changes the CLI display. Do not confuse it with --lang, which sets the language code in the EPUB metadata.

🤖 Non-Interactive Mode (Scripting/Automation)

Besides the question-and-answer mode, WattPDL can also be run through command line arguments, which is great for scheduling (cron/Task Scheduler) or calling from other scripts.

wattpdl --id 398440633 --mode 1 --format docx

Available arguments:

Argument Description
--id Wattpad story ID or link. Setting this enables non-interactive mode.
--mode {1,2,3,4} 1 = everything in 1 file, 2 = everything separate in a .zip, 3 = select several chapters, 4 = select 1 chapter
--format {txt,docx,epub,md,pdf} Output file format. Default: from saved config, or txt
--chapters Chapter numbers for --mode 3, example: 1,3,5-8
--chapter Chapter number for --mode 4, example: 5
--output-dir Custom save folder. Default: from saved config, or the Downloads folder
--skip-existing Skip the download if the target output file already exists, instead of overwriting it
--no-cover Do not embed the story cover image in .docx/.epub/.pdf files
--include-images Also download & embed inline images inside chapters (adds download time)
--workers N Number of chapters downloaded at the same time (default 1)
--no-cache Do not use the story metadata cache, always fetch fresh data
--lang ISO 639-1 language code for EPUB metadata (default id)
--ui-lang {id,en} CLI display language (default en, remembered once chosen)
--user / --user-select Download from an author's story list, optionally selecting which stories
--check-updates Report which downloaded stories have new chapters
--watch / --watch-interval Monitor a story and re-download when new chapters appear (default check interval 1800 seconds)
--no-update-check Do not check for the latest wattpdl version on PyPI at startup
--version Show the wattpdl version

More examples:

# Download all chapters as separate files in a .zip
wattpdl --id 398440633 --mode 2 --format txt

# Download only chapters 1, 3, and 5-8 as 1 combined file
wattpdl --id 398440633 --mode 3 --chapters 1,3,5-8 --format docx

# Download only chapter 10, save to a custom folder
wattpdl --id 398440633 --mode 4 --chapter 10 --output-dir "D:\Wattpad Stories"

# Download all chapters as 1 .epub ebook
wattpdl --id 398440633 --mode 1 --format epub

# Download as Markdown, skip if the file already exists (good for scheduling)
wattpdl --id 398440633 --mode 1 --format md --skip-existing

# Show all options
wattpdl --help

📂 Output Structure

The name and shape of the generated files depend on the mode & format you choose:

Mode .txt format .docx format .epub format .md format .pdf format
1 - All, combined Story_Title.txt Story_Title.docx Story_Title.epub Story_Title.md Story_Title.pdf
2 - All, separate Story_Title.zip (contains: one .txt per chapter) Story_Title.zip (contains: one .docx per chapter) Story_Title.zip (contains: one .epub per chapter) Story_Title.zip (contains: one .md per chapter) Story_Title.zip (contains: one .pdf per chapter)
3 - Several chapters Story_Title_selected.txt Story_Title_selected.docx Story_Title_selected.epub Story_Title_selected.md Story_Title_selected.pdf
4 - One chapter Story_Title_Ch003_Chapter_Name.txt Story_Title_Ch003_Chapter_Name.docx Story_Title_Ch003_Chapter_Name.epub Story_Title_Ch003_Chapter_Name.md Story_Title_Ch003_Chapter_Name.pdf

Content of the combined file (modes 1 & 3): the story title, author, and source at the top, then each chapter separated by a ##### marker.

Story Title
by Author Name
Source: https://www.wattpad.com/story/123456789

==================================================

##### Chapter 1 Title #####

Text of chapter 1...

##### Chapter 2 Title #####

Text of chapter 2...

In the .docx version, the story title becomes the main heading and each chapter automatically becomes a Heading 1 on a new page, so it is comfortable to read right away in Word or Google Docs.

In the .epub version, the story becomes a standard ebook with an automatic table of contents per chapter, ready to open in your favorite ebook reader (Google Play Books, Apple Books, Calibre, and others).

In the .md version, the story is written with standard Markdown headings (# for the title, ## per chapter), which is pleasant to open in any editor or render directly on GitHub/Obsidian/Notion.

If the story has a cover, the image is embedded automatically on the first page/paragraph of the .docx/.epub/.pdf file (unless run with --no-cover). The story's genre/tags, description, and publish date are also saved as official metadata in the .epub file, usually shown on the book detail page in ebook reader apps.

Zip content (mode 2): one file per chapter, numbered by its position in the story, plus 000_info.txt/000_info.md/000_info.docx/000_info.epub/000_info.pdf (matching the format) containing the title, author, and source. The file extension inside the zip follows the format you chose when running the script:

Story_Title.zip
├── 000_info.txt
├── 001_Chapter_1_Title.txt
├── 002_Chapter_2_Title.txt
└── ...

🗺️ Default Folder per OS

Operating System Default Folder
🪟 Windows C:\Users\<username>\Downloads
🍎 macOS /Users/<username>/Downloads
🐧 Linux /home/<username>/Downloads

⚠️ Troubleshooting

Problem Solution
ModuleNotFoundError: No module named 'requests' Run pip install requests
ModuleNotFoundError: No module named 'rich' Run pip install rich
Library 'python-docx' is not installed Run pip install python-docx (only needed if you choose the .docx format)
Library 'EbookLib' is not installed Run pip install EbookLib (only needed if you choose the .epub format)
Library 'reportlab' is not installed Run pip install reportlab (only needed if you choose the .pdf format)
404 error / "No chapters found" Make sure the ID/link is correct & the story is not private
Folder cannot be created Check that the path is valid & you have write permission there
The process hangs on one chapter Check your internet connection and run again, progress will continue

📝 Important Notes

  • The story ID is the number in the Wattpad URL, right after /story/
  • The script uses a public endpoint, no login or API key needed
  • The 0.5 second delay between chapters is set to avoid server rate limits, please do not remove it
  • This script is only for reading your own stories or public stories offline. Respect the authors' copyright

🛠️ Built With

Python Requests Rich python--docx Wattpad API

🗂️ Project Structure

wattpdl/
├── src/
│   └── wattpdl/
│       ├── __init__.py       # package metadata (__version__)
│       ├── __main__.py       # entry point for `python -m wattpdl`
│       ├── app.py            # program flow orchestration (main())
│       ├── api.py            # communication with the Wattpad public API
│       ├── writers.py        # text conversion & writing .txt/.docx/.epub/.md/.pdf/.zip files
│       ├── cli.py            # terminal display (rich), user interaction
│       ├── cli_args.py       # argument parsing for non-interactive mode
│       ├── config.py         # saves user preferences (save folder, format, language)
│       ├── i18n.py           # CLI display translations (en/id)
│       └── progress.py       # download progress cache for the resume feature
├── requirements.txt          # dependency list (for manual reference)
├── pyproject.toml            # package metadata + build config + ruff
├── tests/
│   ├── __init__.py
│   └── test_wattpdl.py       # unit tests (pytest)
├── .github/
│   └── workflows/
│       ├── tests.yml         # CI: automatic test, lint, & build check
│       └── publish.yml       # auto-publish to PyPI on a new release
├── CONTRIBUTING.md           # contribution guide (English)
├── CONTRIBUTING.id.md        # contribution guide (Indonesian)
├── LICENSE
├── README.md                 # main documentation (English)
└── README.id.md              # documentation (Indonesian)

Module separation principles:

  • api.py: knows nothing about the display (rich), purely fetches data
  • writers.py: makes no network requests, purely converts & writes files
  • cli.py: all user interaction & progress bar display
  • cli_args.py: command line argument parsing & validation, no business logic
  • i18n.py: display text dictionary (English/Indonesian), pure data, knows nothing about rich or the network
  • config.py / progress.py: read/write JSON files in ~/.wattpdl/, know nothing about the CLI or the network
  • app.py: ties everything together, with no business logic of its own (invoked through the wattpdl command after install)

🧪 Testing

There are unit tests for the core functions (story ID parsing, file name validation, chapter selection parsing, HTML to text conversion, config, progress/resume, CLI argument parsing, translations, and more).

pip install -e .[dev]
pytest tests/ -v
ruff check .

🤝 Contributing

Want to help improve WattPDL? Read CONTRIBUTING.md for the project structure and contribution flow.

❓ FAQ

Is this legal / safe to use?

This script uses the same public Wattpad endpoint as when you read a story in the browser, so it does not hack anything. But use it responsibly: download for personal/offline reading, and respect the authors' copyright. Do not redistribute or sell other people's stories.

Do I need a Wattpad account?

No. No login or API key is needed at all.

Can I download private / deleted stories?

No. The script can only access stories that are public.

Why does it take so long?

There is a 0.5 second delay between chapters (on purpose, so Wattpad's servers are not overloaded). For stories with hundreds of chapters, it is normal for the process to take a few minutes. You can speed it up with --workers.

Which mode and format should I pick?
  • Want to read from start to finish like a book → Mode 1, the .epub format is the most comfortable in ebook apps
  • Want each chapter as its own file → Mode 2
  • Only need a few specific chapters (for example re-reading a certain part) → Mode 3
  • Just curious about one chapter → Mode 4
  • Want to read casually on a phone/tablet with an ebook app (Google Play Books, Apple Books, etc.) → choose the .epub format
  • Want to edit or print neatly with Word → choose the .docx format
  • Want a small, simple file, or to read it in an e-reader/notes app → choose the .txt format

👤 Author

Nicolas Dwi Dharma
Nicolas Dwi Dharma
github.com/nekonaru

📄 License

Distributed under the MIT License. See LICENSE for more information.

Made with by Nicolas Dwi Dharma

Star ⭐ this repo if this project helps you!

Metadata

Release files for wattpdl 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wattpdl 1.5.0
File Size Uploaded
wattpdl-1.5.0.tar.gz 64.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wattpdl 1.5.0
File Interpreter ABI Platform
wattpdl-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 113.1 kB

Release files / wattpdl-1.5.0.tar.gz

Download URL wattpdl-1.5.0.tar.gz
Size 64.8 kB
Tags Source
SHA-256 checksum
How to use checksums
efc3200e514faba171547f2902fad440472ca90d69e7e0702d03e139f49f7872
BLAKE2b-256 checksum
How to use checksums
fc9caef05b1a484b3a115b471864b5f91aad32d28f885c346fd9a87390128c61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / wattpdl-1.5.0-py3-none-any.whl

Download URL wattpdl-1.5.0-py3-none-any.whl
Size 48.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80ba938dcc5ba7436aa310a2e6035cb347a54f43ff9bdcb829e31e8dbbb6764f
BLAKE2b-256 checksum
How to use checksums
1ed7119b25d9d4ee7280a7c4c1e2dbed8bf2925705c34a23722eca169b4dac71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page