Skip to content

Cloud vs local

The SDK runs preflight in one of three modes. Understanding when to pick each is the single most important design call you'll make with Zotniq.

Mode resolution

client.preflight.check(text, destination, mode="auto") resolves as follows:

mode= client.api_key Result
"auto" (default) set cloud
"auto" unset local
"local" any local (never calls server)
"cloud" set cloud
"cloud" unset raises AuthError immediately
"cloud_with_fallback" set cloud first, local on NetworkError
"cloud_with_fallback" unset raises AuthError

What each mode does

local

  • Regex + Luhn/IBAN/SSN validators + PHI keyword matching
  • Runs entirely in your process
  • Zero network calls, zero telemetry, zero cost
  • Detection surface is bounded: EMAIL, PHONE, SSN, CREDIT_CARD, API_SECRET, IBAN, PHI_KEYWORD, ADDRESS (patterns only, no context)
  • Decision logic: PHI blocks, PII masks, clean passes

Right for: offline apps, air-gapped environments, dev/staging without a key, privacy-sensitive payloads you don't want in Zotniq's audit trail.

cloud

  • POSTs {text, destination} to https://api.zotniq.ai/v1/preflight/text
  • Server runs regex + LLM contextual pass (Team NLP rules)
  • Catches ADDRESS, NAME, custom team-declared kinds (e.g. AIR_TAIL_REG, IN_CLIENT_PII) that regex misses
  • Server writes decision metadata to preflight_audit. The raw text is never persisted (original_preview is always NULL); masked_preview follows the org's retention_mode (FULL keeps it, METADATA nulls it)
  • Response echoes x-request-id for cross-correlation with your Zotniq dashboard

Right for: production apps where you want the full detection surface, teams that want dashboard visibility, customers with contextual/organization-specific rules.

cloud_with_fallback

  • Tries cloud first
  • On NetworkError (5xx, timeout, DNS failure), silently falls back to local
  • On AuthError / ValidationError, raises — those aren't network problems

Right for: production apps where you want cloud's detection surface but can't tolerate an outage cascading into your critical path. Trade-off: some events will only have local-quality findings.

Privacy invariants

Under mode="local": - No network activity. Verifiable with tcpdump. - No content, decision, or finding leaves your process.

Under mode="cloud": - The raw text is sent to Zotniq's server over TLS for evaluation. - The server writes decision metadata to the audit row, never the raw text. The original_preview column is always NULL. masked_preview is written under retention_mode=FULL, nulled under METADATA. - Findings + decision + summary are what your dashboard sees.

If your organization requires the raw text never leaves your perimeter, use mode="local" for those payloads, or self-host Zotniq via base_url=.

Per-call overrides

You can flip modes per call without reconstructing the client:

client = Zotniq(api_key="zot_sk_...")

# 99% of calls go to the cloud
result = client.preflight.check(payload, destination="AI_TOOL")

# This one payload contains something you'd rather not send
result = client.preflight.check(sensitive, destination="AI_TOOL", mode="local")

Self-hosted Zotniq (air-gapped)

Set base_url= to point at your own deployment:

client = Zotniq(
    api_key="zot_sk_...",
    base_url="https://zotniq.internal.acme.com",
)

All cloud-mode calls now go to your infrastructure. On-prem deployment is not a self-service tier today — reach out to sales if you have an air-gapped or in-VPC deployment requirement so we can scope the right delivery.