LEARNING PATHS & COURSES

Qlik Section Access Setup Guide [With Script Templates]

KlarMetrics

October 23, 2025 · 21 min read

This is Article 25 of the Qlik Sense Data Modeling Course.

📚 Qlik Sense Course – Article 25 of 28

Previous Article: Three-Stage Architecture
Next Article: Performance Tuning

What is Section Access? The most powerful security feature in Qlik – Row & Column Level Security directly in the script. Users see only THEIR data, automatically filtered!

Key Insight: Section Access is not a filter. Unauthorized data is permanently removed from RAM before the user sees the app. There is no way for a user to clear it, bypass it, or know it exists. Get the setup wrong and users either see everything or get locked out completely. There is no middle ground.

Section Access is how you control who sees what in Qlik. Get it wrong and users either see everything or get locked out completely. The security table runs at reload time, not at query time. By the time a user opens the app, the data that does not belong to them is already gone from RAM.

Row-level security is not just a technical requirement. For companies with sensitive financial data, getting Section Access right means the CFO sees margin by region while the sales rep only sees their own pipeline. Get it wrong and someone sees numbers they should not. Or the app breaks for everyone. At one mid-sized manufacturer, a misconfigured wildcard in the Section Access table meant every regional sales manager could see every other region’s revenue for six weeks before anyone noticed.

Prerequisites: Basic knowledge of Qlik Load Scripts and the Star Schema data model.

CRITICAL: Section Access can lock you out of your own app! ALWAYS create an ADMIN account with a BLANK reduction before activating Section Access!


What Does This Section Access Setup Guide Cover?

  1. How does Qlik Section Access work?
  2. What System Fields are available in Section Access?
  3. How do you implement Row-Level Security in Qlik?
  4. How do you protect individual columns with OMIT?
  5. What advanced Section Access concepts are there?
  6. What are the differences between Cloud and On-Prem?
  7. Cheat Sheet: Copy & Paste Patterns
  8. Summary & Next Steps

How Does the Architecture and Fundamentals of Qlik Section Access Work?

Section Access filters data at the RAM level by matching a security table against the authenticated user and permanently removing all unauthorized rows from memory. The process runs in 6 steps:

  1. Section Access loads a security table into RAM
  2. User logs into the app (via proxy)
  3. Qlik matches the user against the security table
  4. All Reduction Fields are applied as selections
  5. Non-matching data is PERMANENTLY removed from RAM
  6. The user only sees “their” data — with no way to view anything else

What is the Difference Between Section Access and a Filter?

Section Access is not a filter — it removes data completely from memory. A regular filter leaves the data in RAM and can be changed at any time. Section Access, by contrast, is permanent and invisible.

Aspect Regular Filter Section Access
Data Data stays in RAM Data is removed from RAM
Modifiability User can change/clear the filter Impossible to change in session
Performance All data in memory Only user’s data in memory
Security No real security Real security at data level
Visibility Visible in selections bar Invisible — user doesn’t notice it

What Does the Section Access Script Structure Look Like?

The script structure consists of two sections: Section Access for the security table and Section Application for the normal app code. All field names and values in Section Access are automatically converted to UPPERCASE.

// ===== SECTION ACCESS =====
// This part loads the security table
// EVERYTHING here is converted to UPPERCASE — automatically!

Section Access;

LOAD * INLINE [
    ACCESS, USERID, REGION
    ADMIN, ADMIN,
    USER, DOMAINJOHNDOE, NORTH
];

// ===== SECTION APPLICATION =====
// Normal app code from here on
// Reduction Fields must also be UPPERCASE here!

Section Application;

LOAD
    Upper(Region) as REGION,  // ← MUST be UPPERCASE to match!
    Sales,
    Customer,
    OrderDate
FROM [lib://Data/Sales.qvd] (qvd);

Golden Rule: ALL field names and field values in Section Access are automatically converted to UPPERCASE. That’s why your Reduction Fields in Section Application MUST also be UPPERCASE!

How the data loading process works fundamentally is explained in the first course article.

What Happens Step by Step at Login?

Example: User DOMAINJOHNDOE logs in:

  1. Login: User authenticates at the Qlik Server/Proxy
  2. Match: Qlik looks for DOMAINJOHNDOE in the Section Access table
  3. Found: USERID = DOMAINJOHNDOE, ACCESS = USER, REGION = NORTH
  4. Selection: Qlik automatically sets the selection: REGION = 'NORTH'
  5. Reduction: All rows with REGION ≠ ‘NORTH’ are deleted from RAM
  6. Result: User only sees data with REGION = ‘NORTH’
  7. Permanent: The user CANNOT change or clear this “selection”

Pro Tip: Section Access security is stored in the .qvf/.qvw file itself. Even if a user downloads the app, security remains active!


What System Fields Are Available in Section Access?

Section Access has 7 System Fields that control who sees which data: ACCESS, USERID, USER.EMAIL, NTNAME, GROUP, OMIT, and SERIAL. Each field has a specific purpose.

What is the ACCESS Field in Section Access and What Are the Differences Between ADMIN and USER?

The ACCESS field is mandatory in every Section Access table and determines the permission level. It has exactly 2 possible values: ADMIN and USER.

Section Access;
LOAD * INLINE [
    ACCESS, USERID
    ADMIN, ADMIN_USER      // ← ADMIN Access
    USER, NORMAL_USER       // ← USER Access
];

The key difference: ADMIN sees all data when reduction fails, whereas USER receives “Access Denied”.

Property ADMIN USER
Data Reduction Optional (fallback: all data) Always enforced (strict)
Reload App Yes No
Edit Script Yes No
Missing Reduction Values Shows all data Access Denied
Strict Exclusion Does NOT apply Always applies
OMIT Fields Sees all fields Fields are hidden
Usage Developers, reload accounts Business users

IMPORTANT: ADMIN with data reduction is possible, but it’s not real security! If reduction fails, ADMIN still sees all data. For real security, use the USER access level!

How Do You Configure USERID for On-Premise?

The USERID field identifies the user in Qlik Sense On-Premise via the Windows login in the format DOMAINUsername. It must match the Windows login exactly.

Section Access;
LOAD * INLINE [
    ACCESS, USERID, REGION
    ADMIN, AD_DOMAINADMIN,
    ADMIN, INTERNALSA_SCHEDULER,    // ← Service account for reload!
    USER, AD_DOMAINJOHNDOE, NORTH
    USER, AD_DOMAINJANEDOE, SOUTH
];

USERID Format & Rules:

  • Format: DOMAINUsername
  • Must match the Windows login exactly
  • Case-insensitive: Automatically converted to UPPERCASE
  • Testing: Use the OSUser() function in a KPI to verify the format
  • Wildcard: * = all authenticated users (use with caution!)
// During development: create a KPI with:
=OSUser()

// Output shows e.g.: AD_DOMAINJOHNDOE
// ← That's exactly how USERID must appear in Section Access!

Pro Tip: In production apps: create a “Debug Sheet” (visible to admins only) with OSUser(), OSName(), QlikAuthUser() etc. for troubleshooting! More on Error Handling Strategies.

How Do You Use USER.EMAIL in Qlik Cloud?

In Qlik Cloud, USER.EMAIL is the recommended field for user identification. The email address comes from the Identity Provider (IdP) and rarely changes.

Section Access;
LOAD * INLINE [
    ACCESS, USER.EMAIL, REGION
    ADMIN, ADMIN@COMPANY.COM,
    USER, JOHN.DOE@COMPANY.COM, NORTH
    USER, JANE.DOE@COMPANY.COM, SOUTH
];

USER.EMAIL Details:

  • Format: Standard email address
  • Source: Comes from IdP (Identity Provider) subject claim
  • Case: Case-insensitive (still recommended to use Upper())
  • Testing: Profile icon → Settings shows the email
  • Debug: https://your-tenant.qlikcloud.com/api/v1/diagnose-claims
Field Advantage Disadvantage
USER.EMAIL Simpler, email rarely changes, recommended by Qlik Requires email in security DB
USERID Also works, useful for migration More complex setup, subject claim must be SAM account

Best Practice for Qlik Cloud: Use USER.EMAIL for new apps. Use USERID only when migrating from On-Prem and you don’t want to change the security table. More on this in the Qlik Cloud Migration Guide.

When Should You Use NTNAME Instead of USERID?

NTNAME is a legacy field from QlikView that supports both Windows users and Active Directory groups. That’s the key difference from USERID, which can only match individual users.

Section Access;
LOAD * INLINE [
    ACCESS, NTNAME, REGION
    ADMIN, AD_DOMAINADMIN,
    USER, AD_DOMAINJOHNDOE, NORTH        // ← Individual user
    USER, AD_DOMAINSALES_TEAM, NORTH     // ← AD group!
    USER, AD_DOMAINMANAGER_GROUP, *      // ← Group sees all regions
];
Feature NTNAME USERID
Supports Groups Yes No
Supports Users Yes Yes
Recommended Only when groups are needed When no groups are needed
Performance Slower (group resolution) Faster

Important: Do NOT use NTNAME + USERID in the same row! Both match against the same authentication info — it’s redundant and confusing.

How Does the GROUP Field Work for Group Permissions?

The GROUP field is the modern way to work with groups — cleaner and more flexible than NTNAME. It allows a clear separation between user identification (USERID/USER.EMAIL) and group membership.

Section Access;
LOAD * INLINE [
    ACCESS, USERID, GROUP, REGION
    ADMIN, ADMIN, ,
    ADMIN, INTERNALSA_SCHEDULER, ,
    USER, *, SALES_EMEA, EMEA          // ← Wildcard USERID + GROUP
    USER, *, SALES_AMERICAS, AMERICAS
    USER, AD_DOMAINSPECIAL_USER, , GLOBAL   // ← Individual user
];

Section Application;
LOAD
    Upper(Region) as REGION,
    Sales,
    Country
FROM Sales.qvd;

GROUP Field Advantages:

  • Clean separation: Users in USERID/USER.EMAIL, groups in GROUP
  • Combinable: A user can be in a GROUP and also have an individual USERID
  • Wildcard support: USERID = * + GROUP = XYZ = “all users in group XYZ”
  • Qlik Cloud ready: Supports IdP groups AND custom groups

QlikCloudGroupMode in Qlik Cloud

In Qlik Cloud you can control which groups are used. This is set via a SET variable before Section Access:

// IMPORTANT: Set BEFORE Section Access!

// Mode 0: IdP Groups (Default - from Azure AD, Okta, etc.)
SET QlikCloudGroupMode = 0;

// Mode 1: Custom Groups (defined in Qlik Cloud Admin)
SET QlikCloudGroupMode = 1;

// Mode 2: Both (IdP + Custom Groups)
SET QlikCloudGroupMode = 2;

Section Access;
LOAD * INLINE [
    ACCESS, USER.EMAIL, GROUP, REGION
    USER, *, DATA_ANALYSTS, NORTH
    USER, *, POWER_USERS, *
];

Important for Qlik Cloud: QlikCloudGroupMode is NOT available in Qlik Sense Business or when using the Qlik Identity Provider (IdP). Only available in Qlik Sense Enterprise SaaS with a custom IdP! More details in the Qlik Cloud Security Best Practices article.

How Do You Hide Columns with the OMIT Field?

The OMIT field implements Column-Level Security — it hides entire columns (fields) from specific users. The field simply doesn’t exist for the affected user — it’s not just empty, it’s completely absent.

Section Access;
LOAD * INLINE [
    ACCESS, USERID, REGION, OMIT
    ADMIN, ADMIN, ,
    USER, DOMAINMANAGER, NORTH, SALARY       // ← Cannot see SALARY field
    USER, DOMAINHR_USER, NORTH,              // ← Can see SALARY field
];

Section Application;
LOAD
    Upper(Region) as REGION,
    EmployeeName,
    Upper('Salary') as SALARY,    // ← MUST be UPPERCASE!
    Department
FROM HR.qvd;

OMIT Field Rules:

  • The field does NOT exist for the user (not just empty!)
  • Not visible in the Data Model Viewer
  • Charts using this field show an “Incomplete Visualization” error
  • Can use wildcards: COST* hides all fields starting with COST
  • Can be empty (no fields hidden)

CRITICAL: NEVER use OMIT on Key Fields! This causes Data Model problems and can generate Synthetic Keys. Key fields appear in the Data Model Viewer but are empty — very confusing for users!

What is the Function of the SERIAL Field in Cross-Platform Security?

The SERIAL field enables cross-platform security tables that work across QlikView, Qlik Sense On-Prem, and Qlik Cloud. This lets you maintain a single security table for all platforms.

Section Access;
LOAD * INLINE [
    ACCESS, NTNAME, USER.EMAIL, SERIAL, REGION
    // QlikView user
    USER, AD_DOMAINJOHN, , 4600 0123 4567 8901, NORTH

    // Qlik Sense On-Prem user
    USER, AD_DOMAINJOHN, , QLIKSENSE, NORTH

    // Qlik Cloud user
    USER, , JOHN@COMPANY.COM, QLIKCLOUD, NORTH

    // Admin for all platforms
    ADMIN, ADMIN, ADMIN@COMPANY.COM, *, *
];
SERIAL Value Meaning Platform
* All platforms QlikView + Qlik Sense + Cloud
QLIKVIEW QlikView only QlikView
QLIKSENSE Qlik Sense only Qlik Sense On-Prem
QLIKCLOUD Qlik Cloud only Qlik Cloud
License Number Specific QlikView license QlikView (legacy)

The SERIAL field is especially useful during a migration from QlikView to Qlik Cloud.


How Do You Implement Row-Level Security in Qlik?

Row-Level Security in Qlik is implemented through Reduction Fields in Section Access. There are 5 patterns — from the simple single-field approach to the complex Generic Keys pattern. Which pattern you need depends on the complexity of your permission logic.

How Does Single-Field Reduction Work?

Single-Field Reduction is the simplest pattern: a single field (e.g., REGION) determines which data the user sees. Perfect for simple scenarios like “sales reps only see their region”.

Section Access;
LOAD * INLINE [
    ACCESS, USERID, REGION
    ADMIN, ADMIN,
    ADMIN, INTERNALSA_SCHEDULER,              // ← CRITICAL for reload!
    USER, DOMAINJOHN_SALESREP, NORTH
    USER, DOMAINJANE_SALESREP, SOUTH
    USER, DOMAINMIKE_SALESREP, EAST
    USER, DOMAINSALES_MANAGER, *             // ← Sees all listed regions
];

Section Application;

Sales:
LOAD
    *,
    Upper(Region) as REGION    // ← MUST be UPPERCASE!
FROM [lib://Data/Sales.qvd] (qvd);

What happens when DOMAINJOHN_SALESREP logs in:

  1. Qlik matches: USERID = DOMAINJOHN_SALESREP → REGION = NORTH
  2. Selection is automatically set: REGION = 'NORTH'
  3. All rows with REGION ≠ ‘NORTH’ are deleted from RAM
  4. App now only shows sales for NORTH
  5. The selection is invisible and cannot be changed

Performance benefit — Section Access not only restricts access but also reduces memory usage:

Aspect Without Section Access With Section Access
Rows in RAM 1,000,000 rows 250,000 rows (NORTH only)
App size 500 MB 125 MB
Load time 5 seconds 1.5 seconds

More on performance optimization in Qlik.

How Do You Filter by Multiple Fields at Once?

Multiple Reduction Fields filter across several dimensions simultaneously — e.g., Region AND Country. But be careful: the wildcard * does not mean “all values in the data model”, it means “all values listed in the Section Access table”.

Section Access;
LOAD * INLINE [
    ACCESS, USERID, REGION, COUNTRY
    ADMIN, ADMIN, *, *
    ADMIN, INTERNALSA_SCHEDULER, ,      // ← BLANK = all values (ADMIN only!)
    USER, DOMAINMANAGER1, NORTH, USA
    USER, DOMAINMANAGER2, SOUTH, UK
    USER, DOMAINMANAGER3, NORTH, *      // ← All listed countries
    USER, DOMAINEXEC, *, *              // ← All listed regions + countries
];

Section Application;

Sales:
LOAD
    *,
    Upper(Region) as REGION,
    Upper(Country) as COUNTRY
FROM [lib://Data/Sales.qvd] (qvd);

The Wildcard Problem Explained

This is one of the most common sources of errors. Here’s a concrete example:

// ===== SECTION ACCESS TABLE =====
// MANAGER3 has: REGION = NORTH, COUNTRY = *

USERID, REGION, COUNTRY
MANAGER1, NORTH, USA
MANAGER2, SOUTH, UK
MANAGER3, NORTH, *        // ← * = USA + UK (NOT all countries!)

// ===== APP DATA =====
REGION, COUNTRY, Sales
NORTH, USA, 1000          // ← MANAGER3 sees ✓
NORTH, UK, 500            // ← MANAGER3 sees ✓
NORTH, GERMANY, 800       // ← MANAGER3 does NOT see ✗ (Germany not listed)
NORTH, FRANCE, 600        // ← MANAGER3 does NOT see ✗ (France not listed)
SOUTH, UK, 300            // ← MANAGER3 does NOT see ✗ (SOUTH ≠ NORTH)

Best Practice: If you genuinely need “all values”, create an ADMIN user or explicitly list all possible values in Section Access!

What is the Composite Key Pattern and When Do You Need It?

The Composite Key pattern prevents unwanted cross-products when using multiple Reduction Fields. It combines all values into a single key and is the recommended solution whenever you have more than one Reduction Field.

The Problem with Separate Fields

When you simply use multiple Reduction Fields, all combinations are created (Cartesian product):

// WRONG — unintended combinations
Section Access;
USERID, REGION, COUNTRY
JOHN, NORTH, USA
JOHN, SOUTH, UK

// Problem: JOHN sees:
// NORTH + USA ✓ (intended)
// SOUTH + UK  ✓ (intended)
// NORTH + UK  ✗ (UNINTENDED — Cartesian product!)
// SOUTH + USA ✗ (UNINTENDED — Cartesian product!)

The Solution — a Combined Key

Create a single ACCESS_KEY field that represents the exact combination:

Section Access;
LOAD * INLINE [
    ACCESS, USERID, ACCESS_KEY
    ADMIN, ADMIN,
    ADMIN, INTERNALSA_SCHEDULER,
    USER, DOMAINJOHN, NORTH|USA
    USER, DOMAINJOHN, SOUTH|UK              // ← Only these 2 combinations!
    USER, DOMAINJANE, NORTH|GERMANY
    USER, DOMAINMIKE, EAST|USA
];

Section Application;

Sales:
LOAD
    *,
    Upper(Region) & '|' & Upper(Country) as ACCESS_KEY
FROM [lib://Data/Sales.qvd] (qvd);

This pattern uses the same string concatenation approach you also use when avoiding Synthetic Keys and when designing Link Tables.

Composite Key Best Practices

Do Don’t
Use a unique separator: |, ~~, ### Use spaces (they get trimmed)
Use multiple characters: || or ## Use characters that appear in data: -, _
Document the pattern in the script Change the separator later (breaks security!)
Test with edge cases (nulls, special chars) Forget Upper() on all components

How Do Generic Keys Work for Complex Permissions?

Generic Keys are the most flexible Section Access method for complex permission logic with wildcards like “all regions” or “all products”. The pattern developed by Henric Cronström automatically expands abstract permission symbols into concrete data combinations.

When to use Generic Keys:

  • More than 3 Reduction Fields
  • Many users with similar patterns
  • Business users should maintain the security table (not IT)
  • Complex “ANY” or “ALL” logic is needed
  • Maintainability is more important than simple code

The pattern uses ApplyMap to resolve permission symbols and CROSS JOIN for expansion:

// ===== STEP 1: Security table with generic symbols =====

Section Access;

AUTH_TABLE:
LOAD * INLINE [
    ACCESS, USERID, PRODUCT_AUTH, REGION_AUTH
    ADMIN, ADMIN, *, *
    ADMIN, INTERNALSA_SCHEDULER, ,
    USER, DOMAINUSERA, <PROD_LAPTOP>, <REG_NORTH>
    USER, DOMAINUSERB, <PROD_ALL>, <REG_SOUTH>
    USER, DOMAINUSERC, <PROD_DESKTOP>, <REG_ALL>
    USER, DOMAINUSERD, <PROD_ALL>, <REG_ALL>
];

// ===== STEP 2: Authorization mapping table =====

AUTH_MAPPING:
LOAD * INLINE [
    AUTH_SYMBOL, AUTH_FIELD, AUTH_VALUE
    <PROD_LAPTOP>, PRODUCT, LAPTOP
    <PROD_DESKTOP>, PRODUCT, DESKTOP
    <PROD_TABLET>, PRODUCT, TABLET
    <PROD_ALL>, PRODUCT, *
    <REG_NORTH>, REGION, NORTH
    <REG_SOUTH>, REGION, SOUTH
    <REG_ALL>, REGION, *
];

// ===== STEP 3: Expand generic keys =====

PRD_MAP:
MAPPING LOAD AUTH_SYMBOL, AUTH_VALUE
FROM AUTH_MAPPING WHERE AUTH_FIELD = 'PRODUCT';

REG_MAP:
MAPPING LOAD AUTH_SYMBOL, AUTH_VALUE
FROM AUTH_MAPPING WHERE AUTH_FIELD = 'REGION';

TEMP_PRODUCTS:
LOAD DISTINCT Upper(Product) as PRODUCT
FROM [lib://Data/Sales.qvd] (qvd);

TEMP_REGIONS:
LOAD DISTINCT Upper(Region) as REGION
FROM [lib://Data/Sales.qvd] (qvd);

// Expand for users with "ALL" products
SECURITY_EXPANDED:
LOAD
    ACCESS, USERID,
    If(PRODUCT_AUTH = '<PROD_ALL>', PRODUCT,
       ApplyMap('PRD_MAP', PRODUCT_AUTH, PRODUCT_AUTH)) as PRODUCT_KEY,
    If(REGION_AUTH = '<REG_ALL>', REGION,
       ApplyMap('REG_MAP', REGION_AUTH, REGION_AUTH)) as REGION_KEY
RESIDENT AUTH_TABLE
CROSS JOIN LOAD * RESIDENT TEMP_PRODUCTS
WHERE PRODUCT_AUTH = '<PROD_ALL>';

CONCATENATE (SECURITY_EXPANDED)
LOAD
    ACCESS, USERID,
    ApplyMap('PRD_MAP', PRODUCT_AUTH, PRODUCT_AUTH) as PRODUCT_KEY,
    If(REGION_AUTH = '<REG_ALL>', REGION,
       ApplyMap('REG_MAP', REGION_AUTH, REGION_AUTH)) as REGION_KEY
RESIDENT AUTH_TABLE
CROSS JOIN LOAD * RESIDENT TEMP_REGIONS
WHERE PRODUCT_AUTH <> '<PROD_ALL>';

// Create final composite key
FINAL_SECURITY:
LOAD ACCESS, USERID,
    Upper(PRODUCT_KEY) & '|' & Upper(REGION_KEY) as ACCESS_KEY
RESIDENT SECURITY_EXPANDED;

DROP TABLES AUTH_TABLE, AUTH_MAPPING, TEMP_PRODUCTS, TEMP_REGIONS, SECURITY_EXPANDED;

// ===== SECTION APPLICATION =====
Section Application;

Sales:
LOAD *,
    Upper(Product) & '|' & Upper(Region) as ACCESS_KEY
FROM [lib://Data/Sales.qvd] (qvd);

In complex scenarios this pattern can also be encapsulated as a subroutine.

How Do You Implement Hierarchical Security?

Hierarchical security allows managers to automatically see data from their entire team — including all levels below them. Qlik’s HierarchyBelongsTo function resolves the org structure recursively.

Section Access;

// STEP 1: Load employee-manager hierarchy
EMP_MASTER:
LOAD
    EMPLOYEE_ID, MANAGER_ID,
    Upper(EMPLOYEE_NAME) as EMP_NAME,
    Upper(EMAIL) as EMAIL
FROM [lib://HR/Employees.qvd] (qvd);

// STEP 2: Create hierarchy with HierarchyBelongsTo
HIERARCHY_TABLE:
HierarchyBelongsTo(EMPLOYEE_ID, MANAGER_ID, EMP_NAME,
                   MANAGER_ID, MANAGER_NAME, DEPTH)
LOAD EMPLOYEE_ID, MANAGER_ID, EMP_NAME
RESIDENT EMP_MASTER
WHERE not IsNull(MANAGER_ID);

// STEP 3: Create Section Access with rollup
SECTION_ACCESS_FINAL:
LOAD
    'USER' as ACCESS,
    'DOMAIN' & Upper(EMP_NAME) as USERID,
    Upper(MANAGER_NAME) as EMP_ID_REDUCTION,
    If(DEPTH = 0, '', 'SALARY') as OMIT
RESIDENT HIERARCHY_TABLE
WHERE DEPTH >= 0;

// STEP 4: Add HR admin
CONCATENATE (SECTION_ACCESS_FINAL)
LOAD * INLINE [
    ACCESS, USERID, EMP_ID_REDUCTION, OMIT
    ADMIN, DOMAINHR_ADMIN, ,
    ADMIN, INTERNALSA_SCHEDULER, ,
];

DROP TABLES EMP_MASTER, HIERARCHY_TABLE;

Section Application;

HR_DATA:
LOAD
    Upper(EMPLOYEE_ID) as EMP_ID_REDUCTION,
    EMPLOYEE_NAME,
    Upper('Salary') as SALARY,
    DEPARTMENT, PERFORMANCE_RATING
FROM [lib://HR/EmployeeData.qvd] (qvd);

How Does HierarchyBelongsTo Work?

HierarchyBelongsTo resolves parent-child relationships recursively. DEPTH = 0 means the employee themselves, DEPTH = 1 is a direct report, DEPTH = 2 is a report’s report.

Input Output Meaning
EMP: CEO, MANAGER: null CEO → CEO (Depth 0) CEO sees themselves
EMP: VP, MANAGER: CEO VP → VP (Depth 0), VP → CEO (Depth 1) VP sees themselves. CEO sees VP.
EMP: JOHN, MANAGER: VP JOHN → JOHN (D0), JOHN → VP (D1), JOHN → CEO (D2) Every manager above sees JOHN.

Pro Tip: HierarchyBelongsTo is perfect for org charts! For the underlying data modeling, a clean fact-dimension design is important.


How Do You Protect Individual Columns with OMIT?

Column-Level Security with OMIT hides entire columns from specific users. The field doesn’t exist for the affected user — it’s not just empty, it’s simply not there.

How Does the OMIT Group Pattern Work?

The OMIT Group pattern scales Column-Level Security for many users and many fields. Instead of creating one row per user and field, you define groups of fields to be hidden.

Bad solution — one row per field:

// INEFFICIENT — 10+ rows for ONE user
Section Access;
ACCESS, USERID, OMIT
USER, JOHN, SALARY
USER, JOHN, BONUS
USER, JOHN, SSN
USER, JOHN, MEDICAL_INFO
USER, JOHN, BANK_ACCOUNT

Good solution — OMIT Group table:

Section Access;

SECURITY:
LOAD * INLINE [
    ACCESS, USERID, REGION, OMITGROUP
    ADMIN, ADMIN, ,
    USER, DOMAINMANAGER, NORTH, SENSITIVE_HR
    USER, DOMAINANALYST, NORTH,
    USER, DOMAINCONTRACTOR, SOUTH, ALL_FINANCIALS
];

OMIT_FIELDS:
LOAD * INLINE [
    OMITGROUP, OMIT
    SENSITIVE_HR, SALARY
    SENSITIVE_HR, BONUS
    SENSITIVE_HR, SSN
    SENSITIVE_HR, MEDICAL_INFO
    ALL_FINANCIALS, COST
    ALL_FINANCIALS, PROFIT
    ALL_FINANCIALS, MARGIN
];
Without OMIT Group With OMIT Group
100 users × 10 fields = 1,000 rows 100 users + 10 fields = 110 rows
Difficult to maintain Easy to add new fields
Error-prone (copy-paste) Change one group → all users updated

How Do You Use OMIT with Wildcards?

Wildcards in OMIT hide multiple fields at once. It’s recommended to use consistent naming conventions during data transformation to take advantage of this:

Section Access;
LOAD * INLINE [
    ACCESS, USERID, OMIT
    USER, DOMAINUSER1, COST*         // ← Hides: COST, COST_TOTAL, COST_PER_UNIT
    USER, DOMAINUSER2, *SALARY*      // ← Hides: SALARY, BASE_SALARY, GROSS_SALARY
    USER, DOMAINUSER3, INTERNAL_*    // ← Hides: INTERNAL_NOTES, INTERNAL_ID
];

Best Practice — Naming Conventions: Use prefixes/suffixes for sensitive fields to leverage wildcards! Example: prefix all cost fields with COST_, then OMIT: COST_*.

How Do You Resolve the “Incomplete Visualization” Error?

When a chart uses an OMITted field, Qlik shows the error “Incomplete visualization”. Here are 3 proven solutions:

Solution 1: Conditional Show at chart level

// Chart Properties → Add-ons → Show condition:
 FieldIndex('SALARY', 1) > 0

// Chart is only displayed when the SALARY field exists

Solution 2: Alternative charts in a container

// Chart 1: With SALARY (Show Condition: FieldIndex('SALARY', 1) > 0)
=Sum(SALARY)

// Chart 2: Without SALARY — fallback (Show Condition: FieldIndex('SALARY', 1) = 0)
='Salary information not available for your user'

Solution 3: Field existence check in expression

=If(FieldIndex('SALARY', 1) > 0,
   Sum(SALARY),
   Null())

OMIT Best Practices & Common Mistakes

Don’t Why not Alternative
OMIT on key fields Data model chaos, synthetic keys Dummy field or mask the value
OMIT in charts without handling Incomplete visualization error Conditional show or field check
OMIT in master dimensions Master item becomes unusable Create alternative master items
OMIT without documentation User doesn’t understand why charts are missing Document + fallback message

What Advanced Section Access Concepts Are There?

What is the Difference Between Initial Selection and Initial Data Reduction?

In Qlik Sense there is only Initial Data Reduction — Strict Exclusion is always active. QlikView, however, had two modes that could be configured in Document Properties → Opening tab.

Property Initial Selection (QlikView) Initial Data Reduction (recommended)
Data All data in RAM Permanently reduced
User can Change/clear selections NOT change
Security NO real security! Real data security
Usage Testing, sheet hiding PRODUCTION

Best Practice for QlikView: ALWAYS use “Initial Data Reduction Based on Section Access” + “Strict Exclusion” in production! “Initial Selection” is only for testing.

How Does Strict Exclusion Work in Detail?

Strict Exclusion determines what happens when a user has a Reduction Value that does NOT exist in the data. In Qlik Sense it is always active. In QlikView you had to enable it.

Setting User sees Security level
Strict Exclusion OFF ALL data SECURITY RISK!
Strict Exclusion ON “Access Denied” error Secure

CRITICAL: Strict Exclusion OFF = security vulnerability! NEVER use in production!

Make sure all Reduction Values actually exist in the data. A Data Quality Check in the load script helps with this.

What is the Difference Between BLANK, Wildcard *, and a Specific Value?

There are 3 options for Reduction Values in Section Access:

Option Meaning Only for Use case
BLANK (empty) All values in the data model (truly all!) ADMIN Reload account, development
* All listed values in Section Access ADMIN or USER Manager sees all assigned regions
NORTH Only this specific value USER Regular user with restriction

IMPORTANT: BLANK only works for the ADMIN access level! A USER with BLANK gets “Access Denied” (Strict Exclusion).


The cloud implementation has a different setup that catches most teams off guard. Section Access in Qlik Cloud vs on-premise covers the key differences before you migrate.

What Are the Differences Between Cloud and On-Prem Section Access?

The main difference lies in user identification: On-Premise uses USERID with Windows domain accounts, while Qlik Cloud recommends USER.EMAIL via the Identity Provider.

Field On-Prem Qlik Cloud
USERID Recommended (AD_DOMAINUSER) Possible, but complex
USER.EMAIL Not available RECOMMENDED
NTNAME For groups Legacy (use GROUP instead)
GROUP AD groups IdP + custom groups
Strict Exclusion Configurable Always active
QlikCloudGroupMode Not available 0, 1, or 2

For a detailed migration guide, see the Qlik Cloud Migration Strategy Guide and the GDPR Compliance Guide for data protection requirements.


How Do I Copy and Paste Patterns from the Section Access Cheat Sheet?

Here are the most common Section Access patterns ready to copy directly. Each pattern is production-ready — just remember to adapt the USERIDs and field names to your environment.

What is Basic Row Reduction?

Section Access;
LOAD * INLINE [
    ACCESS, USERID, REGION
    ADMIN, ADMIN,
    ADMIN, INTERNALSA_SCHEDULER,
    USER, DOMAINJOHN, NORTH
];

Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;

How Do Multiple Fields with Composite Key Work in Section Access?

Section Access;
LOAD * INLINE [
    ACCESS, USERID, ACCESS_KEY
    ADMIN, ADMIN,
    USER, DOMAINJOHN, NORTH|USA
];

Section Application;
LOAD *, Upper(Region) & '|' & Upper(Country) as ACCESS_KEY
FROM Data.qvd;

How Can I Use OMIT Fields in Section Access?

Section Access;
LOAD * INLINE [
    ACCESS, USERID, OMIT
    USER, DOMAINJOHN, SALARY
];

Section Application;
LOAD Upper('Salary') as SALARY, * FROM Data.qvd;

How Does Qlik Cloud with USER.EMAIL Work in Section Access?

Section Access;
LOAD * INLINE [
    ACCESS, USER.EMAIL, REGION
    ADMIN, ADMIN@COMPANY.COM,
    USER, JOHN@COMPANY.COM, NORTH
];

Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;

What Are Groups in Qlik Cloud?

SET QlikCloudGroupMode = 0;

Section Access;
LOAD * INLINE [
    ACCESS, USER.EMAIL, GROUP, REGION
    USER, *, SALES_TEAM, NORTH
];

Section Application;
LOAD Upper(Region) as REGION, * FROM Data.qvd;

It’s best to integrate Section Access into your Three-Stage Architecture — the UPPERCASE conversion belongs in the Transform Layer.


What Are the Key Takeaways and Next Steps for Section Access?

What Are the 5 Golden Rules for Section Access?

  1. ALWAYS create an ADMIN account with BLANK reduction
  2. ALWAYS add the reload account (SA_SCHEDULER/Owner)
  3. ALL fields and values must be UPPERCASE
  4. Enable Strict Exclusion (QlikView) — Qlik Sense always has it on
  5. TEST, TEST, TEST before going to production!

Where Do You Go From Here?

Pick the path that fits where you are:

  • Moving to Qlik Cloud? The setup for Cloud is different enough that it deserves its own read. Section Access: Cloud vs On-Prem differences covers USER.EMAIL, IdP groups, QlikCloudGroupMode, and the migration traps that break security silently.
  • Building the full data layer? Section Access security fields belong in the Transform Layer of a proper architecture. The Qlik Data Modeling Course walks through all 28 layers from raw data to production-ready apps.
  • Performance too slow after adding Section Access? A security table that doubles your RAM usage is not a configuration problem — it’s a data model problem. Performance Tuning covers the patterns that keep Section Access apps fast even at scale.

What would help you most right now?

Thanks!