Install Laidline
Read this if you are about to install Laidline on a workstation, a server or in a container image. You will pick the extras for what you mark, install them with the right PyTorch build, download the model weights ahead of time and check the install. Skip if Laidline is already installed and you want a first marked file (Quickstart). Time: 5 minutes plus downloads (about 2 minutes on a fast connection). Needs: Python 3.12 or newer, pip, and network access to PyPI, the PyTorch index and Hugging Face.
Before you start
-
Python 3.12 or newer. Check it:
python3 --versionExpected output:
Python 3.12.xor a later version. Older versions cannot install Laidline. -
A virtual environment, so Laidline and its PyTorch build do not mix with other projects:
python3 -m venv .venv && . .venv/bin/activate
-
Disk: about 1.2 GB for an environment with the media extras on the CPU build of PyTorch, plus about 2 GB for the model weights (the tables below).
1. Choose your extras
pip install laidline installs the core only. Everything that marks media or runs a server is an extra in brackets.
Pick by what you mark and how you run it:
| Extra | What it enables | Installed size (CPU PyTorch) |
|---|---|---|
| (none) | the core: configuration, signing with a local key, the evidence log on files, licence and issuer checks, the laidline command |
43 MB |
image |
image marking and detection: PixelSeal (the default) and TrustMark watermarks, Content Credentials | +0.96 GB |
audio |
audio marking and detection: AudioSeal, in any container PyAV reads | +0.99 GB |
video |
video marking and detection: VideoSeal (the default) or keyframe TrustMark; add audio to mark the soundtrack |
+1.07 GB |
text |
text watermark detection (KGW and SynthID); marking runs in the laidline-vllm and laidline-transformers plugins |
+0.97 GB |
server |
laidline serve: the native routes, the OpenAI-compatible proxy and metrics |
+23 MB |
ingest |
laidline ingest: the storage hook for S3 with SQS, R2 with Queues, or a local directory |
+22 MB |
kms |
signing with AWS KMS or Vault/OpenBao Transit | +22 MB |
evidence |
S3 and Postgres evidence sinks | +42 MB |
gcs |
Google Cloud Storage ingest (Cloud Run) | +9 MB |
lambda |
the AWS Lambda runtime entry for the storage hook | +21 MB |
all |
every extra above except lambda |
about 1.2 GB |
The audio and video extras bring PyAV from PyPI, whose wheel bundles FFmpeg with the GPL libraries libx264 and
libx265; video is encoded with libx264 by default. For an install without them, take PyAV and an LGPL FFmpeg with
OpenH264 from conda-forge and set watermark.video.encoder: libopenh264
(Video: Encoding without x264; the licences:
Third-party licences).
The media extras share PyTorch, so a combination costs little more than one of them: image,audio,server installs
to 1.13 GB and image,audio,video,text,server to 1.22 GB (Linux x86_64, Python 3.12, CPU PyTorch). The
audio and text extras each install without image.
A typical first install is image,audio,server: you can mark images and audio from the command line, from Python and
over HTTP. A production host adds kms (a managed signing key) and usually evidence (a shared evidence sink); see
Production.
2. Install PyTorch for your hardware
The media extras depend on PyTorch. The default PyTorch build on PyPI includes CUDA, also on a host without a GPU: about 3.2 GB to download and a 5.7 GB environment. On a CPU-only host, install the CPU build first, so the extras find it already in place:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
Expected output (the last line; versions vary):
Successfully installed ... torch-2.14.1+cpu torchvision-0.29.1+cpu ...
What just happened: pip installed the CPU build of PyTorch from the PyTorch index. When you install the Laidline
extras next, pip sees that torch is already satisfied and keeps this build.
With uv, uv pip install "laidline[image,audio,server]" --torch-backend cpu does both steps in one.
On a GPU host you can keep the default CUDA build from PyPI, or install the CUDA 13 build first:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130
The CUDA 13 build needs an NVIDIA driver of release 580 or newer and a GPU of compute capability 7.5 or newer (Turing and later). Check that PyTorch sees the GPU:
python -c "import torch; print(torch.cuda.is_available())"
Expected output: True. Laidline uses the GPU on its own (watermark.device: auto). A GPU matters most for video:
VideoSeal on a CPU takes seconds per second of video. See Video.
3. Install Laidline
pip install "laidline[image,audio,server]"
Expected output (the last line, shortened):
Successfully installed ... laidline-1.0.1 ...
Then check the command:
laidline --version
Expected output:
1.0.1
What just happened: pip installed Laidline 1.0.1 with the image, audio and server extras on top of the PyTorch
build from step 2, and put the laidline command on your path.
The plugins are separate packages that install laidline with the extras they need: laidline-comfyui,
laidline-diffusers, laidline-vllm, laidline-transformers, laidline-pipecat and laidline-livekit
(Integrations). The benchmark harness is laidline-bench (Benchmarks).
4. Download the model weights
The watermark models are not part of the package. They download on first use, which makes the first mark (or the
start of laidline serve) wait, without progress output, for up to 1.65 GB. Download them now instead:
laidline models fetch
Expected output (one line per file, with your home directory and the host each file came from):
/home/you/.cache/laidline/models/audioseal/generator_base.pth (58805980 bytes, from huggingface.co) /home/you/.cache/laidline/models/audioseal/detector_base.pth (34667641 bytes, from huggingface.co) /home/you/.cache/laidline/models/audioseal/generator_streaming.pth (58805126 bytes, from huggingface.co) /home/you/.cache/laidline/models/audioseal/detector_streaming.pth (34668361 bytes, from huggingface.co) /home/you/.cache/laidline/models/videoseal/y_256b_img.pth (228351471 bytes, from dl.fbaipublicfiles.com) /home/you/.cache/laidline/models/pixelseal/model.pth (308952624 bytes, from dl.fbaipublicfiles.com)
What just happened: Laidline downloaded the pinned weights, checked each file's SHA-256 and stored them under
$LAIDLINE_HOME/models (~/.cache/laidline/models when LAIDLINE_HOME is unset). The PixelSeal checkpoint is kept
beside the slimmed copy it prints (the slimmed copy's size can differ by a few kilobytes between PyTorch versions).
The AudioSeal and PixelSeal downloads took 22 seconds on a fast connection.
| Weights | Download | Flag to skip it |
|---|---|---|
| PixelSeal (default image scheme) | 1.24 GB checkpoint, slimmed to a 309 MB copy; 1.55 GB on disk | --no-image |
| VideoSeal 1.0 | 228 MB | --no-video |
| AudioSeal (generator and detector, batch and streaming) | 187 MB for the four files | --no-audio |
A speech-only host needs laidline models fetch --no-video --no-image (AudioSeal only). An image and audio host
without video can skip VideoSeal with --no-video. The TrustMark scheme, if you select it, fetches its own weights on
first use.
laidline models fetch does not fetch the TrustMark Q decoder's ONNX graph (decoder_Q.fp32.onnx, 94,773,826 bytes) that the
keyframe video reader uses. The reader fetches it on first use, checked against its pin, unless LAIDLINE_OFFLINE=1; on an
offline host copy it beside the other models ($LAIDLINE_HOME/models/trustmark/), or the reader runs on torch with a warning
(Licences). The Docker images ship it.
For a host without internet access, run laidline models fetch on a connected machine, copy
$LAIDLINE_HOME/models across, and set LAIDLINE_OFFLINE=1 on the offline host so that nothing tries to download.
If the connected machine cannot reach the upstream hosts either, set LAIDLINE_MODELS_MIRROR to the https base URL of a
mirror of the weights, such as Laidline's own https://laidline.com/models (it holds the TrustMark Q decoder graph; your
own copy works too): Laidline tries <base>/<file> first and falls back to the pinned URL when the mirror
does not answer or serves a file that does not match. The pinned SHA-256 decides what is accepted from either.
Check it worked
Ask Python for the versions Laidline will run with:
python -c "import laidline, torch; print(laidline.__version__, torch.__version__, torch.cuda.is_available())"
Expected output on a CPU-only host:
1.0.1 2.14.1+cpu False
+cpu and False confirm the CPU build; on a GPU host with the CUDA 13 build you see +cu130 and True. The
Quickstart continues from here: write a configuration, mark, detect and serve.
Run it in a container instead
Laidline is a Python package, so a container image is a Python image with the same two install lines. This
Dockerfile (change the version to the release you want) builds a CPU image for the sidecar with the weights inside,
runs as a non-root user and keeps the configuration and the evidence log on a volume at /var/lib/laidline:
FROM python:3.12-slim RUN useradd --uid 10001 --create-home laidline \ && mkdir -p /opt/laidline /var/lib/laidline \ && chown laidline /opt/laidline /var/lib/laidline RUN pip install --no-cache-dir torch torchvision --index-url https://download.pytorch.org/whl/cpu \ && pip install --no-cache-dir "laidline[image,audio,server]==1.0.1" ENV LAIDLINE_HOME=/opt/laidline LAIDLINE_CONFIG=/var/lib/laidline/laidline.yaml USER laidline WORKDIR /var/lib/laidline RUN laidline models fetch --no-video EXPOSE 8080 HEALTHCHECK --start-period=90s CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/readyz')" ENTRYPOINT ["laidline"] CMD ["serve", "--host", "0.0.0.0"]
Build it, write a starter configuration into the volume, and start the sidecar:
docker build -t laidline:1.0.1 . docker run --rm -v laidline-data:/var/lib/laidline laidline:1.0.1 init --system-name my-image-model --org "Yourcompany Inc" docker run -d --name laidline -p 127.0.0.1:8080:8080 -v laidline-data:/var/lib/laidline laidline:1.0.1 curl -s localhost:8080/readyz
Expected output of the last command, a few seconds after the start:
{"ready":true,"error":null}
What just happened: the image holds Laidline, the CPU PyTorch build and the PixelSeal and AudioSeal weights (about
2 GB to pull). The container serves on all its interfaces (--host 0.0.0.0, which a container needs), and
-p 127.0.0.1:8080:8080 publishes the port to this host only. laidline.yaml, the development certificate and the
evidence log live in the laidline-data volume. For a GPU image, start from a CUDA base image and install PyTorch
from the cu130 index instead. Before real traffic, follow Production: a managed key, a shared
evidence sink and the inbound token.
The MIT licence notices of the model families travel with the package: the installed laidline distribution carries a
THIRD_PARTY_NOTICES file in its metadata, and the images Laidline builds also copy it to
/usr/share/doc/laidline/THIRD_PARTY_NOTICES. See Third-party licences.
Limits
- The installed sizes above are measured on Linux x86_64 with Python 3.12 and CPU PyTorch; with the CUDA build from PyPI the environment is about 5.7 GB.
- Laidline needs the weights on disk before it marks or detects the first file of a medium; without them that first call waits for the download. Mark latency once loaded is in Benchmarks.
- VideoSeal on a CPU is slow (seconds per second of video); use a GPU for production video (Video).
Troubleshooting
| Message | Cause | Fix |
|---|---|---|
Requires-Python >=3.12 or requires a different Python |
Your Python is older than 3.12 | Install Python 3.12 or newer and create the virtual environment with it. |
ModuleNotFoundError: No module named 'PIL' from laidline mark |
The core was installed without a media extra | pip install "laidline[image]" (or audio, video). |
ModuleNotFoundError: No module named 'uvicorn' from laidline serve |
The server extra is missing |
pip install "laidline[server]", with your other extras in the same brackets. |
| The environment is about 5.7 GB on a host without a GPU | pip installed the CUDA build of PyTorch from PyPI | Uninstall torch and torchvision, install them from the CPU index (step 2), then reinstall the extras. |
The first mark or the start of laidline serve hangs for minutes |
The weights are downloading (no progress output) | Wait, or stop and run laidline models fetch first. |
torch.cuda.is_available() prints False on a GPU host |
The CPU build is installed, or the driver is older than the CUDA build needs | Install PyTorch from the cu130 index with a driver of release 580 or newer. |
Reference
- Quickstart: your first mark, detect and sidecar, continuing from this page
- Production: register, a managed signing key, a shared evidence sink and the security settings
- Configuration: every key, including
watermark.device - Command line:
laidline models fetchand every other command - Integrations: which plugin or path fits where your outputs are produced
- Third-party licences: the licences of the model weights and libraries