Skip to main content

TikLocal

Your own TikTok for the videos and photos you already have.
Self-hosted, offline, no account, no cloud.

PyPI License

TikLocal Library grid on desktop with the Flow swipe feed on a phone

TikLocal turns a folder of media into a private feed. Run one command on your computer or NAS, open it on your phone, and swipe through your own videos and photos full screen — or browse them as a Pinterest-style grid and a year/month timeline. Nothing leaves your machine.

Quick start

pip install tiklocal
tiklocal ~/Videos

Open http://<your-computer>:8000 on any phone, tablet, or browser on the same network. The first start prints an access password in the terminal.

What it does

  • Flow — a full-screen vertical feed that mixes videos and images. Swipe to the next item, double-tap to favorite, hold a video to play it at 2×, and drag sideways to seek.
  • Library — a year/month timeline for multi-year archives and an Explore grid with random images, latest videos, and large files.
  • Home — pick up where you left off, see what happened On This Day, and open your collections.
  • Favorites and collections — save anything from any view; long videos resume where you stopped, across devices.
  • Downloads — paste a link and TikLocal fetches it into your library with yt-dlp or gallery-dl.
  • Radio — an ambient audio player for the music in the same folders.
  • Many folders, one library — merge several media directories; deletions go to a trash you can undo.

Flow: a full-screen waterfall video with like, save and info actions Home: a collage of recent photos with entry points to Flow and Radio Library: a two-column grid of landscape and city photos

Home on desktop with the On This Day row

Screenshots use CC0 and public-domain photos and clips from Wikimedia Commons.

Flow controls

Gesture Video Image
Swipe up / down, wheel, ↑ ↓ Next / previous Next / previous
Tap Play / pause Show / hide the interface
Double-tap Favorite Favorite
Press and hold 2× while held Show / hide the interface
Drag sideways Seek Next image in a gallery
← → Back / forward 5 s Gallery image, otherwise next / previous

Files the browser cannot play (for example some HEVC or AV1 videos) are skipped with a short note instead of stopping the feed.

Configuration

Settings come from command-line options, then environment variables (MEDIA_ROOT, TIKLOCAL_HOST, TIKLOCAL_PORT), then ~/.config/tiklocal/config.yaml:

media_sources:
  - id: default
    name: Main Library
    path: ~/Videos/TikLocal
  - id: photos
    name: Photos
    path: ~/Pictures
download_source: default   # where URL downloads are saved
name: Studio Mac           # shown in the browser tab
port: 8000

A single media_root: ~/Videos still works. Sources are merged into one library; media URIs look like @source_id/path, and old bare-path links and favorites keep working through the default source.

tiklocal /path/to/media                        # start with one folder
tiklocal --port 9000                           # custom port
tiklocal --media-source photos=~/Pictures/AI   # add a source (repeatable)
tiklocal --help

Access password

Sign-in is on by default. Every page, API and media file requires it.

tiklocal auth status          # status and storage path
tiklocal auth set-password    # new password; signs out existing sessions
TIKLOCAL_AUTH_PASSWORD='a-long-private-password' tiklocal auth set-password

The password is stored as a scrypt hash in ~/.tiklocal/auth.json. Keep TikLocal on a trusted network.

HTTPS

TikLocal serves plain HTTP. For HTTPS, put it behind a reverse proxy that keeps the original Host header and media Range requests, and mark the session cookie secure:

FLASK_AUTH_COOKIE_SECURE=true tiklocal ~/Videos --host 127.0.0.1 --port 8000

URL downloads

The /download page queues background downloads. Install the tools it uses:

brew install yt-dlp gallery-dl ffmpeg        # macOS
sudo apt install yt-dlp gallery-dl ffmpeg    # Ubuntu / Debian
  • yt-dlp (required) handles video sites; TikLocal asks it for H.264/AAC so downloads play in every browser. gallery-dl handles image posts and albums. ffmpeg merges formats and makes video thumbnails.
  • For sign-in-only content, put exported cookie files in ~/.tiklocal/cookies with the domain in the name (x.com.txt, youtube.com.cookies), or upload them on the download page.

Stopping the server (Ctrl + C or SIGTERM) cancels unfinished downloads and keeps finished files; interrupted jobs are not resumed.

More commands

Thumbnails

tiklocal thumbs /path/to/media              # generate video thumbnails
tiklocal thumbs /path --overwrite           # regenerate

Duplicates

tiklocal dedupe /path/to/media              # dry run
tiklocal dedupe /path --type video          # videos only
tiklocal dedupe /path --keep newest --execute

Options: --type video|image|all, --algorithm sha256|md5, --keep oldest|newest|shortest_path, --dry-run (default), --execute, --auto-confirm.

AI titles and similar images (optional)

Image titles and tags use a vision model; similar images use an embedding model. Both are off unless configured:

vision:
  enabled: true
  base_url: https://openrouter.ai/api/v1
  model_name: google/gemini-2.5-flash
  tags_limit: 5

experiments:
  similarity:
    enabled: true

embedding:
  enabled: true
  base_url: https://openrouter.ai/api/v1
  model_name: google/gemini-embedding-2
  dimensions: 768
  image_max_size: 512
  image_quality: 82

API keys come from TIKLOCAL_VISION_API_KEY, TIKLOCAL_EMBEDDING_API_KEY, then TIKLOCAL_AI_API_KEY, OPENAI_API_KEY or OPENROUTER_API_KEY.

Vectors are built from the command line and stored in ~/.tiklocal/tiklocal.sqlite3; viewing results never calls a model.

tiklocal vectorize ~/Videos --dry-run                  # see what would be sent
tiklocal vectorize ~/Videos --limit 200 --order latest
tiklocal vectorize ~/Videos --source photos --cleanup
tiklocal analyze-similar ~/Videos --limit 500 --yes

Only missing or stale images are uploaded, resized and re-encoded without their original metadata. Results appear at /experiments/similarity, opened from Settings. experiments.similarity.enabled: false turns the feature off without deleting data; restart after changing it. When omitted, a valid legacy embedding.enabled: true enables it. Precedence is defaults < YAML < saved embedding configuration < CLI options.

Embedding in another WSGI server

The CLI owns the download manager. When hosting create_app() yourself, call app.extensions['download_manager'].start() inside the serving worker and .close() in its shutdown hook — not in Flask's per-request teardown.

Upgrading from versions with built-in HTTPS or PWA

Built-in HTTPS, certificate management, PWA installation and offline caching were removed. Remove https, tls_cert, tls_key and hostnames from the YAML configuration; active old TLS settings stop startup rather than silently switching to HTTP. The --https, --tls-cert, --tls-key, --hostname options, tls commands and the [https] extra are gone. Files under ~/.tiklocal/tls/ are left untouched. Revisit the same address once to retire the old service worker; old home-screen shortcuts can be removed by hand.

LumaFold for iPhone and Android

apps/radio contains LumaFold, a local-first native client. It imports photos and videos you pick into a private offline Flow with no account, network, or server, and can optionally connect to your TikLocal server for Radio. See docs/radio-native-client-architecture.md.

Documentation

Contributing

Bug reports, ideas and pull requests are welcome on GitHub. To refresh the screenshots, serve a demo folder without sign-in and run the capture script (it uses your installed Chrome):

npm install
FLASK_AUTH_ENABLED=false tiklocal demo-media --port 8793
node scripts/screenshots.mjs

Contact: chan.mo@outlook.com

License

MIT

Metadata

Release files for TikLocal 0.8.44

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

Source distribution (sdist)

Source distribution for TikLocal 0.8.44
File Size Uploaded
tiklocal-0.8.44.tar.gz 2.7 MB Details

Built distribution (wheel)

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

Total release size: 5.5 MB

Release files / tiklocal-0.8.44.tar.gz

Download URL tiklocal-0.8.44.tar.gz
Size 2.7 MB
Tags Source
SHA-256 checksum
How to use checksums
f2f93e3d5c76c6e87e91d7d3e56b193beab1f3a7a9fa89230c11214b04c2bc68
BLAKE2b-256 checksum
How to use checksums
1f24bc6c05a9dd712a28e71245e2a01df638fb876f875835d802e74589bf745d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

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 1, 2026.

Transparency log

Release files / tiklocal-0.8.44-py3-none-any.whl

Download URL tiklocal-0.8.44-py3-none-any.whl
Size 2.8 MB
Tags Python 3
SHA-256 checksum
How to use checksums
fb34b35bf799457178077b17a7845ccab7b3ccbd5b611a71f48ef557dadd4e4a
BLAKE2b-256 checksum
How to use checksums
f94a2387fa5a77a2507fe493ca6942f9e21c62adfa6c4ea806f2dca28bce83fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

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 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.44 This release

2 release files

0.8.43

2 release files

0.8.41

2 release files

0.8.39

2 release files

0.8.38

2 release files

0.8.37

2 release files

0.8.36

2 release files

0.8.35

2 release files

0.8.34

2 release files

0.8.33

2 release files

0.8.32

2 release files

0.8.31

2 release files

0.8.30

2 release files

0.8.29

2 release files

0.8.28

2 release files

0.8.27

2 release files

0.8.19

2 release files

0.8.18

2 release files

0.8.17

2 release files

0.8.16

2 release files

0.8.15

2 release files

0.8.14

2 release files

0.8.13

2 release files

0.8.12

2 release files

0.8.10

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.1

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

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