Paperless-ngx: Automated Workflows, OCR Optimization, and Custom Rules (Part 2)

Take control of your document management. Optimize OCR settings, configure custom import workflows, and automate document categorization.

1. Advanced OCR Optimization and Engine Settings

To achieve maximum accuracy and performance, you must tune Tesseract within Paperless-ngx. Modify your Docker environment variables (docker-compose.env or the environment: block in docker-compose.yml) to adjust OCR behavior.

# Define the OCR mode. Options: skip (default), force, redo, skip_noarchive.
# Use 'skip' to only run OCR on documents that do not have embedded text.
# Use 'force' to run OCR on all documents, overriding pre-existing text layers.
PAPERLESS_OCR_MODE=skip

# Install and enable multiple OCR languages (space-separated, lowercase ISO 639-3 codes)
# Ensure corresponding language packs are available or downloaded.
PAPERLESS_OCR_LANGUAGES=eng deu fra

# Limit the number of pages processed per document to prevent resource exhaustion.
# Setting to 0 disables the limit (default).
PAPERLESS_OCR_PAGES=0

# Pass custom parameters directly to Tesseract.
# "oem": OCR Engine Mode (3 = Default, based on what's available).
# "tessedit_char_whitelist": restrict OCR to specific characters if processing raw forms.
PAPERLESS_OCR_USER_ARGS='{"oem": 3, "presorted_langs": true}'

For multi-core hosts, you can control the resource utilization of OCR processing:

# Set the maximum number of parallel threads Tesseract is allowed to use per page.
# By default, Tesseract uses all available cores. Limit this to prevent CPU starvation.
OMP_THREAD_LIMIT=2

# Number of parallel document tasks Paperless-ngx handles.
# Equal to the number of concurrent celery workers.
PAPERLESS_WEBSERVER_WORKERS=2
PAPERLESS_TASK_WORKERS=2

2. Mounting and Configuring the Consume Folder via NFS/Samba

When ingestion occurs from a network scanner or a remote server, mounting the consume folder over NFS or Samba requires tuning to avoid file locks, permission mismatches, and missed file-system events.

Samba (CIFS) Mount Configuration

Add the share to your host's /etc/fstab to ensure a persistent mount:

//192.168.1.50/scans /mnt/paperless-consume cifs credentials=/etc/samba/credentials,uid=1000,gid=1000,iocharset=utf8,vers=3.0,nofail,x-systemd.automount 0 0

NFS Mount Configuration

Alternatively, if using NFS:

192.168.1.50:/volume1/scans /mnt/paperless-consume nfs rsize=1048576,wsize=1048576,timeo=600,retrans=2,nofail,x-systemd.automount 0 0

Docker Compose Bind Mount & Permission Matching

Map the local mount point into the container. You must ensure the environment variables USERMAP_UID and USERMAP_GID match the owner of the network share.

services:
  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: paperless-webserver
    environment:
      - USERMAP_UID=1000
      - USERMAP_GID=1000
      # Force polling because network filesystems do not reliably trigger inotify events
      - PAPERLESS_CONSUMER_POLLING=10
      # Delay in seconds to wait after a file is detected before consuming it
      # Prevents paperless from consuming a file that is still being written
      - PAPERLESS_CONSUMER_INOTIFY_DELAY=5
    volumes:
      - /mnt/paperless-consume:/usr/src/paperless/consume
      - paperless-data:/usr/src/paperless/data
      - paperless-media:/usr/src/paperless/media

3. Automated File Classification & Matching Rules

Paperless-ngx matching algorithms dictate how tags, correspondents, document types, and storage paths are automatically assigned to incoming documents.

Match Type Algorithm / Logic Best Use Case Matching Rule Example
None No automatic assignment. Manual triaging. N/A
Any Matches if any listed word is found (case-insensitive). Grouping various related terms. invoice bill statement
All Matches if all listed words are found (case-insensitive). Precise compound matching. electric utility service
Exact Matches the exact string, including spaces. Fixed strings or titles. Acme Corp LLC
Regular Expression Python-style regex matches the text. Complex patterns (IDs, VATs). \bDE[0-9]{9}\b
Fuzzy Matches using Levenshtein distance similarity. Scanned documents with poor OCR. Telekom
Auto Naive Bayes classifier trained on existing documents. High-volume structured document streams. N/A

Setting Up a RegEx Match Rule for Invoices

To automatically assign the tag Invoice using a regular expression match rule: 1. Navigate to Tags -> Create. 2. Name the tag: Invoice. 3. Set Matching algorithm to Regular Expression. 4. Set Matching pattern to search for invoice numbers or currency notations: regex (?i)\b(invoice|rechnung|facture|bill)\b


4. Advanced Email Fetching Configurations

Automate the processing of electronic invoices, receipts, and bank statements directly from your mailboxes.

IMAP Connection Setup

Navigate to Settings -> Mail Accounts -> Add Account: - IMAP Server: imap.protonmail.ch (or your mail provider's address) - Port: 993 - Security: SSL/TLS - Username & Password: Use a dedicated App Password.

Custom Mail Rules

Configure granular mail rules via Settings -> Mail Rules -> Add Rule:

# Conceptual logic executed by Paperless-ngx Mail Rule Parser
Rule-Name: "Utility Bill Parser"
Trigger-On: "Inbox"
Filter-Criteria:
  Sender-Contains: "billing@utilityprovider.com"
  Subject-Contains: "your invoice"
  Has-Attachment: True
Processing-Action:
  Extract-Attachment: "Only attachments matching pattern: *.pdf"
  On-Success: "Mark as read and archive email"
Assign-Metadata:
  Tag: "Utility"
  Correspondent: "Utility Provider"
  Document-Type: "Invoice"

To configure this in the UI: 1. Source: Select your configured Mail Account. 2. Folder: INBOX (or a subfolder like Invoices). 3. Filter From: billing@utilityprovider.com. 4. Filter Subject: your invoice. 5. Action: Process attachments. 6. Action parameter: *.pdf. 7. Assign Tag: Utility. 8. Assign Correspondent: Utility Provider. 9. Assign Document Type: Invoice.


5. Custom Document Workflows and Automation Triggers

Workflows (introduced in Paperless-ngx v2.0+) execute actions based on triggers and conditions. This replaces the legacy post-consume scripts for most routing tasks, though they can still run in tandem.

Workflow Example: Direct Routing and Slack Webhook

In this scenario, whenever a document tagged High Priority is consumed, a custom webhook is executed to alert the team.

Step 1: Create the Post-Consume Script

Write a Python script /usr/src/paperless/scripts/post-consume-webhook.py inside the container:

#!/usr/bin/env python3
import os
import sys
import requests

# Paperless-ngx passes environment variables containing document context
document_id = os.environ.get("DOCUMENT_ID")
document_title = os.environ.get("DOCUMENT_TITLE")
document_tags = os.environ.get("DOCUMENT_TAGS")
download_url = f"https://paperless.local/api/documents/{document_id}/download/"

webhook_url = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"

payload = {
    "text": f"๐Ÿšจ *New Document Processed* ๐Ÿšจ\n*Title:* {document_title}\n*Tags:* {document_tags}\n*Link:* <{download_url}|Download PDF>"
}

try:
    response = requests.post(webhook_url, json=payload, timeout=10)
    response.raise_for_status()
    print("Notification sent successfully.")
except Exception as e:
    print(f"Failed to send webhook: {e}", file=sys.stderr)
    sys.exit(1)

Make sure the script is executable:

chmod +x /usr/src/paperless/scripts/post-consume-webhook.py

Step 2: Configure Environment for External Scripts

Add the script path to your Docker compose configuration to allow Paperless-ngx to run it:

PAPERLESS_POST_CONSUME_SCRIPT=/usr/src/paperless/scripts/post-consume-webhook.py

Step 3: Define Custom UI Workflows

Go to Workflows in the Paperless-ngx Web UI: 1. Create Workflow: - Name: Archive Financial Docs 2. Trigger: - Type: Document Added - Source: Consume Folder - Filter: Document matches Invoice tag. 3. Action: - Type: Assign Storage Path - Storage Path: {{ year }}/{{ correspondent }}/{{ title }} - Add Tag: Archived