Cloud Conversions

Qlik Sense client-managed → Qlik Cloud object migration kit & runbook

Download the migration kit qlik-migration-kit.zip — all scripts, classification map, docs. Contains no client data.

Architecture at a glance

Apps arrive in the client's Qlik Cloud tenant via QAMT (exact on-premise app, permissions included). All work happens inside one shared space restricted to developers — apps are never published; "publish" always means sheet visibility within that space. Original sheet IDs are preserved end-to-end so bookmarks stay intact; the kit re-creates each sheet's contents as cloud-born objects (full property export → new object created by the Cloud engine → grid-cell swap), guaranteeing every object is registered as cloud-created and receives future cloud feature updates. Frozen "(Original)" clone sheets in a public "Original" group are the visual reference and part of the rollback safety net.

Coverage (verified Sep 2026): the classification map is reconciled against qlik.dev's authoritative visualization type-ID reference — 91 object types including both id spellings bundle charts can carry (plain type ids like funnelchart / wordcloud and their sn-* nebula ids). 72 Qlik-to-Cloud conversions run ungated (56 identity re-creations); every Qlik object type has a conversion path. The only exceptions are the correct ones: Share button (replaced by the publish bookmark capability), Multi KPI (removed from Cloud, rebuild), and NL Insights (manual migration per Qlik).

The lifecycle

1 --preflight → 2 dry-run (plan) → 3 --execute + inline verify → 4 review verification → 5 client sign-off → 6 --promote → 7 --cleanup → 8 --decommission
  1. Preflight (once per tenant/space): validates every schema assumption live — write capability, sheet cloning, container children refs, layout geometry keys, sheet-group schema, publish rights → preflight_report.json. First create one sheet group manually in the test app so the group schema can be confirmed. --execute refuses to run without a passing preflight.
  2. Dry-run: prints the complete per-app action plan. The orchestrator is a plan/execute split — execute applies exactly the printed plan; the two cannot drift.
  3. Execute (per app): canary "object testing" sheet proves edit rights → every sheet (hidden ones included) is cloned as "(Original) <name>", grouped, published → working sheets go private → masters, sheet cells, and container children convert to the standard targets. Every conversion is verified immediately; the first instance of each conversion type must pass before bulk conversion of that type, and a circuit breaker halts the app after repeated findings. Originals are never destroyed at this stage.
  4. Review verification_report.csv; run scan_stories.py for story/snapshot references to old object ids.
  5. Sign-off with the client on the converted (still private) sheets while consumers keep seeing the frozen Original clones.
  6. Promote: the explicit go-live — publishes the converted working sheets. Refuses while unresolved "attention" verifications exist (--force overrides).
  7. Cleanup: destroys original objects only where the conversion verified.
  8. Decommission: removes the "(Original)" sheets and group so apps don't carry doubled sheets forever.

Safety model

Four-tier recovery (rollback_app.py --app <id>)

  1. Whole-app QVF backup — with QLIK_CLI_BACKUP=1, qlik-cli exports each app to qvf_backups/ before any change; a failed backup aborts the app untouched.
  2. Orphaned original — still exists until cleanup; swap the cell back. Fast and exact.
  3. JSON export replay — full pre-conversion property trees.
  4. "(Original)" clone copy — every duplicated sheet holds an exact copy of each original object at the same grid position; located automatically, and always available for manual recovery by simply opening the "(Original) <name>" sheet. (Master-item instances on clones follow the shared converted master — tiers 1-2 cover those.)

What's in the kit

FilePurpose
qlik_engine.pyShared Engine API session: retry with backoff, throttling (QLIK_THROTTLE_MS), JSON-RPC recording (QLIK_RECORD) + offline replay.
qlik_cloud_inventory.pyPrimary crawler: recursive walk of every app in the space — sheets, master visualizations, container children (native + Vizlib), master-instance resolution, orphaned objects.
qlik_object_inventory.pyOn-prem/Desktop crawler variant; hosts the shared crawl logic.
analyze_inventory.pyScores every object: vendor, legacy flag, deprecation date, latest version, cloud-native equivalent, compatibility %, version status. Per-app rollup + unmapped-type discovery.
object_classification_map.csvThe knowledge base: 91 object types with authoritative ids from qlik.dev (both bundle id spellings), verified against Qlik's deprecation timelines (May 2027 removals, retired classic table, legacy Text & image), incl. newer objects like Write table and Navigation menu. The accumulating asset — carry the latest copy.
make_approval_worklist.pySeeds/refreshes the approval worklist; human decisions survive reruns.
restructure_app_sheets.pyThe orchestrator: preflight, plan/dry-run, execute (steps 01-09 incl. 13-step container rebuilds and cloud-born re-creation), promote, cleanup, decommission, discover.
rollback_app.pyObject-level rollback across the four recovery tiers (see above).
scan_stories.pyFinds story/snapshot references to converted (old) object ids; names the replacement id per hit.
test_planner.pyOffline planner test against a fake engine — run anywhere, no tenant needed.
conversion_analysis_app.qvsLoad script for the Conversion Analysis app: scored inventory + map + approvals + audit + verification in one Qlik data model.
build_analysis_app.pyBuilds the Conversion Analysis app in the tenant automatically: five dashboard sheets (Overview, Object Explorer, Legacy & Deadlines, Conversion Progress, Approvals) of cloud-born native objects, load script pre-set. Upload the output CSVs to the space data files and reload.
AGENTS.mdCanonical cross-AI agent guide (Claude, ChatGPT/Codex, Gemini, Grok, Cursor …): inviolable rules, env vars, lifecycle commands, architectural invariants, Qlik MCP + qlik-cli guidance.
README.md / CLAUDE.mdFull runbook; CLAUDE.md is a thin pointer to AGENTS.md.

Client-environment setup

  1. Python 3.8+, then pip install websocket-client (the kit's only dependency).
  2. Claude Code: install per claude.com/claude-code and sign in with the company account. The kit's AGENTS.md briefs any AI assistant automatically (CLAUDE.md points Claude to it).
  3. Download & unzip the kit from this page into a working folder; open the folder in Claude Code.
  4. Tenant API key: Profile settings → API keys (developer role required).
  5. Environment variables:
    QLIK_TENANT   = clienttenant.region.qlikcloud.com
    QLIK_API_KEY  = <api key>
    QLIK_SPACE_ID = <designated shared-space GUID>
  6. Sanity check offline: python test_planner.py
  7. Inventory first: python qlik_cloud_inventory.py → python analyze_inventory.py → add any unmapped_types.csv rows to the map → python make_approval_worklist.py → review in the Conversion Analysis app.
  8. Then the lifecycle above, piloting one app with --app <id> before the fleet.
Corporate proxy (this environment has one): the kit tunnels WebSocket traffic through HTTPS_PROXY / https_proxy automatically (QLIK_PROXY overrides; NO_PROXY and user:pass@host:port supported). If the proxy intercepts TLS, set QLIK_CA_BUNDLE=<corporate-root.pem> (QLIK_INSECURE_TLS=1 is a loud last-resort while obtaining it). pip may need --proxy and --trusted-host pypi.org --trusted-host files.pythonhosted.org; Claude Code honors HTTPS_PROXY too. Ask IT to allow WebSocket (wss/443) upgrades to *.qlikcloud.com and HTTPS to api.anthropic.com / claude.ai — some proxies block WebSocket upgrades outright, which looks like a hang at "Crawling ...".

AI integration (works with any assistant)

Open decisions & reminders