Skip to content

Configuration Reference

Paperless NGX Dedupe uses:

  • Environment variables for server/runtime behavior
  • Dedup settings stored in the app database and editable at runtime

Environment Variables

Core Runtime

VariableRequiredDefaultNotes
PAPERLESS_URLYes-Full Paperless-NGX URL (for example http://paperless:8000)
PAPERLESS_API_TOKENYes*-Preferred auth method
PAPERLESS_USERNAMENo-Use with PAPERLESS_PASSWORD when not using token
PAPERLESS_PASSWORDNo-Use with PAPERLESS_USERNAME
DATABASE_URLNo./data/paperless-ngx-dedupe.dbSQLite file path
PORTNo3000Web/API listen port
LOG_LEVELNoinfodebug, info, warn, error
CORS_ALLOW_ORIGINNoemptyEmpty = same-origin only; * = allow all
AUTO_MIGRATENotrueAuto-run DB schema migration on startup

* Provide either PAPERLESS_API_TOKEN or both PAPERLESS_USERNAME + PAPERLESS_PASSWORD.

If both token and username/password are set, token is used first.

Paperless connection settings and all credentials are environment-owned. The Settings page exposes the configured URL as read-only and only reports whether authentication is configured; it never reads, stores, exports, or accepts these values through the database or configuration API. Existing legacy credential rows in app_config are removed during startup migration. Keep the values in your deployment environment or secret manager when moving an installation.

Container Runtime

VariableRequiredDefaultNotes
PUIDNo1000UID used inside the container
PGIDNo1000GID used inside the container

SvelteKit / Proxy

VariableRequiredDefaultNotes
ORIGINUsually no-Set when running behind reverse proxies or non-localhost hostnames to satisfy origin checks

AI Processing (Optional)

VariableRequiredDefaultNotes
AI_ENABLEDNofalseEnable AI-powered document classification
AI_OPENAI_API_KEYWhen AI enabled-OpenAI API key

The API key is required when AI_ENABLED=true. Runtime settings (model, prompt, etc.) are configured in the Settings page or via API. See AI Processing for full details.

Observability (Optional)

OpenTelemetry is off unless OTEL_ENABLED=true. Common vars:

  • OTEL_ENABLED
  • OTEL_SERVICE_NAME
  • OTEL_EXPORTER_OTLP_ENDPOINT (or per-signal endpoints)
  • OTEL_TRACES_EXPORTER, OTEL_METRICS_EXPORTER, OTEL_LOGS_EXPORTER

See .env.example for the full list.

VariableRequiredDefaultNotes
OTEL_SERVICE_NAMESPACENopaperless-dedupeGroups frontend and backend as one app in Grafana Cloud App Observability
OTEL_EXPORTER_OTLP_COMPRESSIONNo(none)Set to gzip for Grafana Cloud (recommended)
OTEL_SEMCONV_STABILITY_OPT_INNo(none)Set to database to use stable DB semantic conventions

Continuous Profiling (Optional)

VariableRequiredDefaultNotes
PYROSCOPE_ENABLEDNofalseEnable wall-time and heap profiling
PYROSCOPE_SERVER_ADDRESSWhen Pyroscope enabled-Grafana Cloud Pyroscope endpoint or self-hosted URL
PYROSCOPE_BASIC_AUTH_USERFor Grafana Cloud-Grafana Cloud instance ID
PYROSCOPE_BASIC_AUTH_PASSWORDFor Grafana Cloud-Grafana Cloud API key

Profiles are labeled by operation (sync, analysis, ai_batch, worker) for flame graph filtering.

Prometheus Scrape Endpoint (Optional)

VariableRequiredDefaultNotes
OTEL_PROMETHEUS_ENABLEDNofalseExpose a Prometheus scrape endpoint at /api/v1/metrics

When enabled, all application metrics (sync, analysis, jobs, AI, observable gauges) are available in Prometheus exposition format at GET /api/v1/metrics. This can be used standalone (without OTEL_ENABLED) or alongside full OTEL for both push and pull metrics.

When both are active, the Prometheus endpoint exposes the same metrics as the OTLP pipeline.

Paperless-NGX System Metrics (Optional)

When enabled, Paperless NGX Dedupe collects system-level metrics from your Paperless-NGX instance — storage, document counts, tags, correspondents, and more. This provides the same observability as running a separate prometheus-paperless-exporter container, but delivered through whichever metrics pipeline you have active (OTLP, Prometheus, or both) — one fewer container to manage.

For the supported collectors, metric names match the Prometheus exporter (for example, paperless_status_storage_total_bytes and paperless_statistics_documents_total) for Grafana dashboard compatibility. Exporter collectors that this application does not provide, such as individual task and log metrics, are not exposed.

Separately opt-in

This is opt-in independently of OTEL_ENABLED / OTEL_PROMETHEUS_ENABLED because collectors poll the Paperless-NGX API every export interval (~60s), adding load to your Paperless instance. Enable only the collectors you need if this is a concern.

VariableRequiredDefaultNotes
PAPERLESS_METRICS_ENABLEDNofalseEnable Paperless system metrics collection. Requires OTEL_ENABLED=true or OTEL_PROMETHEUS_ENABLED=true.
PAPERLESS_METRICS_COLLECTORSNoallComma-separated list of collectors to enable

Paperless-NGX 3.x applies permissions to system-wide observability data. The API user needs paperless.view_system_monitoring for the status collector. Grant paperless.view_global_statistics if the statistics and document collectors should report global counts; without it, Paperless returns counts limited to objects visible to that user.

Available collectors:

CollectorAPI CallsDescription
status1Storage, database, Redis, Celery, index, classifier, and sanity check status
statistics1 + paginated on Paperless 2.xDocument totals, inbox count, file type breakdown, character count, metadata counts
document1 (shared with statistics)Total document count
tagpaginatedPer-tag info, document counts, inbox flag
correspondentpaginatedPer-correspondent info, document counts, last correspondence timestamp
document_typepaginatedPer-document-type info and document counts
storage_pathpaginatedPer-storage-path info and document counts
group1User group count
user1User count
remote_version1Update availability check (causes Paperless-NGX to make an outbound network call)

All collectors are enabled by default. To enable only specific collectors:

PAPERLESS_METRICS_COLLECTORS=status,statistics,document

Metrics are collected on the same interval as OTEL metric exports (controlled by OTEL_METRIC_EXPORT_INTERVAL, default 60s). Instances with many tags, correspondents, or document types will produce proportionally more time series from the labeled collectors (tag, correspondent, document_type, storage_path). Disable these if cardinality is a concern.

Credit: metric definitions and collector design inspired by prometheus-paperless-exporter by hansmi.

Deduplication Settings

Change these in Settings or via PUT /api/v1/config/dedup.

Algorithm Parameters

SettingDefaultRangeNotes
numPermutations25616-1024MinHash signature length
numBands321-100LSH bands; should divide numPermutations evenly
ngramSize31-10Word shingle size
minWords201-1000Skip very short docs below this
similarityThreshold0.750-1Minimum overall similarity to keep a pair
fuzzySampleSize10000100-100000Character sample size for fuzzy compare
autoAnalyzetruebooleanAuto-run analysis after sync

Confidence Weights

The confidence model uses a 2-weight base score plus a discriminative penalty:

Base weights are integers 0-100 and must sum to 100:

SettingDefaultNotes
confidenceWeightJaccard60Weight for Jaccard (set overlap) similarity
confidenceWeightFuzzy40Weight for fuzzy (edit distance) similarity

Discriminative penalty reduces confidence when template-based documents have different structured data (dates, amounts, invoice numbers, routes):

SettingDefaultRangeNotes
discriminativePenaltyStrength700-100How aggressively differing structured data reduces confidence (0 = disabled)

The final confidence formula is:

base  = (jaccard × J_weight + fuzzy × F_weight) / (J_weight + F_weight)
final = base × (1 - penalty_strength/100 × (1 - discriminative_score))

When the discriminative score is high (documents share the same dates, amounts, and references), the penalty has little effect. When it is low (documents have different dates, amounts, invoice numbers, or routes despite sharing a template), the penalty reduces the confidence score.

Strength guidelines:

  • Low (0-30%): Minimal impact. Monthly invoices or train tickets with different dates may still appear as duplicates.
  • Medium (40-70%): Recommended for most libraries. Catches template-based false positives while keeping true duplicates intact.
  • High (80-100%): Aggressive. Best for libraries with many monthly invoices, bank statements, or train/flight tickets. May over-penalize minor OCR differences in dates or amounts.

When any weight or penalty strength changes, existing group confidence scores are recalculated automatically.

Example API Updates

# Update threshold
curl -X PUT http://localhost:3000/api/v1/config/dedup \
  -H 'Content-Type: application/json' \
  -d '{"similarityThreshold":0.8}'

# Rebalance weights (must sum to 100)
curl -X PUT http://localhost:3000/api/v1/config/dedup \
  -H 'Content-Type: application/json' \
  -d '{
    "confidenceWeightJaccard":70,
    "confidenceWeightFuzzy":30
  }'

# Adjust discriminative penalty strength (0 = disabled, 100 = maximum)
curl -X PUT http://localhost:3000/api/v1/config/dedup \
  -H 'Content-Type: application/json' \
  -d '{"discriminativePenaltyStrength":75}'