Do not input private or sensitive data. View Qlik Privacy & Cookie Policy.
Skip to main content

Announcements
Streamlining user types in Qlik Cloud capacity-based subscriptions: Read the Details
cancel
Showing results for 
Search instead for 
Did you mean: 
muhammedraleen
Partner - Creator II
Partner - Creator II

Need to connect Qlik Engine API and getData()

Hi Team,

As of now, I have Qlik Sene Desktop. I have a Student Statement App, and i have created a straight table in the format they need. Now, using Qlik Engine API can I connect to this app and get that table data from using .net or JS. So, I can use the data in my custom app for other purposes.

Is this Possible? If yes, what's the best method? I see Qlik Engine API, Capability APIs.

Please anyone help me on this at your earliest convenience.


1 Solution

Accepted Solutions
muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi Team,
Below is qlikservice.js... Anyone who needs, can refer this.
I have connected to Qlik Engine and view all apps, sheets and its object details. Used gethypercubedata method for extracting data from charts. To extract from Filterpane listboxes, used GetListObjectData method.

const enigma = require('enigma.js');
const WebSocket = require('ws');
const schema = require('enigma.js/schemas/12.170.2.json');

const QLIK_HOST = process.env.QLIK_HOST || 'localhost:4848';

const createSession = (appId = null) => {
    const url = `ws://${QLIK_HOST}/app/${appId || ''}`;
    return enigma.create({
        schema,
        url,
        createSocket: (url) => new WebSocket(url),
    });
};

const getApps = async () => {
    const session = createSession();
    try {
        const global = await session.open();
        const docList = await global.getDocList();
        await session.close();
        return docList;
    } catch (err) {
        console.error('Error fetching apps:', err);
        throw err;
    }
};

const getAppStructure = async (appId) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);

        // Get Sheets
        const sheetListObject = await app.createSessionObject({
            qInfo: { qType: 'SheetList' },
            qAppObjectListDef: {
                qType: 'sheet',
                qData: { title: '/qMetaDef/title', description: '/qMetaDef/description' },
            },
        });

        const sheetLayout = await sheetListObject.getLayout();
        const sheets = sheetLayout.qAppObjectList.qItems.map(item => ({
            id: item.qInfo.qId,
            title: item.qData.title,
        }));

        // For each sheet, list objects
        const structure = [];
        for (const sheet of sheets) {
            const sheetObj = await app.getObject(sheet.id);
            const sLayout = await sheetObj.getLayout();

            let objectIds = [];

            // Method 1: Get from ChildInfos
            const children = await sheetObj.getChildInfos();
            objectIds = children.map(c => c.qId);

            // Method 2: Get from cells (common for standard sheets)
            if (sLayout.cells && objectIds.length === 0) {
                objectIds = sLayout.cells.map(cell => cell.name);
            }

            const objects = [];
            for (const id of objectIds) {
                try {
                    const childObj = await app.getObject(id);
                    const childLayout = await childObj.getLayout();

                    // Try multiple paths for title
                    const title = childLayout.title ||
                        childLayout.qMetaDef?.title ||
                        (childLayout.showTitles && childLayout.title) ||
                        'Untitled Object';

                    objects.push({
                        id: id,
                        type: childLayout.qInfo.qType,
                        title: title,
                    });
                } catch (childErr) {
                    console.warn(`Could not fetch details for object ${id}:`, childErr.message);
                }
            }

            structure.push({
                ...sheet,
                objects
            });
        }

        await session.close();
        return structure;
    } catch (err) {
        console.error(`Error fetching structure for app ${appId}:`, err);
        if (session) await session.close();
        throw err;
    }
};

const getObjectData = async (appId, objectId) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);
        const obj = await app.getObject(objectId);
        const layout = await obj.getLayout();

        if (!layout.qHyperCube) {
            throw new Error('Object does not contain a HyperCube');
        }

        const hc = layout.qHyperCube;
        const headers = [
            ...hc.qDimensionInfo.map(d => ({ label: d.qFallbackTitle, type: 'dimension' })),
            ...hc.qMeasureInfo.map(m => ({ label: m.qFallbackTitle, type: 'measure' }))
        ];

        // Fetch data (simple paging for first 100 rows, can be expanded)
        const qPage = [{ qTop: 0, qLeft: 0, qHeight: 100, qWidth: headers.length }];
        const dataPages = await obj.getHyperCubeData('/qHyperCubeDef', qPage);

        const rows = dataPages[0].qMatrix.map(row => {
            return row.map(cell => cell.qText || cell.qNum);
        });

        await session.close();
        return { headers, rows, title: layout.title || 'Data' };
    } catch (err) {
        console.error(`Error fetching data for object ${objectId} in app ${appId}:`, err);
        if (session) await session.close();
        throw err;
    }
};

const getStudentFilters = async (appId, selections = {}) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);

        // Map UI keys to Qlik Field Names
        const fieldMap = {
            Company: 'Company',
            Branch: 'Branch',
            StudentID: 'Student_ID',
            StudentName: 'Student Name'
        };

        // Apply existing selections to the app session
        for (const [key, values] of Object.entries(selections)) {
            if (values && values.length > 0) {
                try {
                    const fieldName = fieldMap[key];
                    const qField = await app.getField(fieldName);
                    // Convert values to Qlik selection format
                    const qValues = values.map(v => ({ qText: v.toString() }));
                    await qField.selectValues(qValues, false); // false = replace existing selections in this session
                } catch (selectErr) {
                    console.warn(`Could not apply selection for ${key}:`, selectErr.message);
                }
            }
        }

        const listboxMap = {
            Company: '1ab18293-be8e-497e-9d32-84aaa708375d',
            Branch: '2b04e7a7-919a-4696-9e9b-8bc323251739',
            StudentID: '2d864310-d740-473a-bb09-24d97ce3dcd0',
            StudentName: 'af924ba2-a043-46e3-a5e5-3dcfff4d44ab'
        };


        const result = {};

        for (const [key, id] of Object.entries(listboxMap)) {
            console.log(`Fetching data for filter: ${key} (ID: ${id})`);
            try {
                const obj = await app.getObject(id);
                const layout = await obj.getLayout();

                if (!layout.qListObject) {
                    console.warn(`Object ${id} is not a Listbox or has no qListObject property.`);
                    result[key] = [];
                    continue;
                }

                const totalRows = layout.qListObject.qSize.qcy;
                const items = [];
                const pageSize = 10000;

                for (let top = 0; top < totalRows; top += pageSize) {
                    const pages = [{ qTop: top, qLeft: 0, qHeight: pageSize, qWidth: 1 }];
                    const data = await obj.getListObjectData('/qListObjectDef', pages);

                    if (data && data[0] && data[0].qMatrix) {
                        data[0].qMatrix.forEach(row => {
                            if (row[0]) {
                                // Only add if Selected (S) or Optional/Possible (O)
                                // Standard Qlik states: S=Selected, O=Optional, X=Excluded, A=Alternative
                                const state = row[0].qState;
                                if (state === 'S' || state === 'O') {
                                    let val = row[0].qText || row[0].qNum;
                                    if (val !== undefined && val !== null && val !== '') {
                                        val = val.toString();
                                        if (key === 'StudentName') val = val.toUpperCase();
                                        items.push(val);
                                    }
                                }

                            }
                        });
                    }

                }
                result[key] = items.sort();
                console.log(`Found ${items.length} unique values for ${key}`);
            } catch (objErr) {
                console.error(`Error fetching listbox ${id}:`, objErr.message);
                result[key] = [];
            }
        }

        await session.close();
        return result;
    } catch (err) {
        console.error('Error fetching student filters via listboxes:', err);
        if (session) await session.close();
        throw err;
    }
};


module.exports = {
    getApps,
    getAppStructure,
    getObjectData,
    getStudentFilters
};

View solution in original post

8 Replies
Øystein_Kolsrud
Employee
Employee

I guess your solution depends on how you want to use the extracted data. But here is a simple example of how to use the .NET SDK in C# to connect to an app in Qlik Sense Desktop, extract data from a table, and write it to standard output:

static void Main(string[] args)
{
   var objId = "<objectId>";
   var location = Location.FromUri("http://localhost:4848");
   location.AsDirectConnectionToPersonalEdition();

   var appId = location.AppWithNameOrDefault("MyApp");
   using (var app = location.App(appId))
   {
      var obj = app.GetGenericObject(objId);
      var pager = obj.GetHyperCubePager("/qHyperCubeDef");
      foreach (var cellRow in pager.GetAllData())
      {
         Console.WriteLine(string.Join("\t", cellRow.Select(c => c.Text)));
      }
   }
}

You can read more about the .NET SDK here:

https://help.qlik.com/en-US/sense-developer/November2025/Subsystems/NetSDKAPI/Content/Sense_NetSDKAP...

The .NET SDK is available for download from NuGet:

https://www.nuget.org/packages/QlikSense.NetSDK/

muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi @Øystein_Kolsrud,

The above solution I tried, and it worked for me in Qlik Sense Desktop. I'm developing .NET app, so the desktop/console app supports the Qlik. Engine but for web-based .NET app we need to use web sockets; above solution I cannot use for web-based applications.

Please support me on working on web-based app and thanks for the above as well.

Øystein_Kolsrud
Employee
Employee

But can't you use the .NET SDK if you're building a .NET based web application?

muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi @Øystein_Kolsrud ,

I need a sample code to achieve the above in .NET web-based app?

muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi Team,

I need to use my extracted in my front-end tables, filters created. Can I use .NET to get data from my object or do i need to use Qlik Engine JSON API also to achieve it ?

Øystein_Kolsrud
Employee
Employee

I'm not a web developer, so I'm not really the best person to guide you in what is the best way forward. But the .NET SDK is primarily a .NET wrapper for the Qlik Engine JSON API. If you want to extract data from an app, then there is no other way than to use web sockets. And that library provides a way to do so in .NET.

muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi @Øystein_Kolsrud,

As .NET is little confusing and complicated; I'm trying to develop a .JS framework project and use web sockets to connect app and get data. As .JS can be understandable and easy, and used React for the Front End. I'm working on that, if anyone can support on this, please...! 

If I got the working code, I'll upload it here.

muhammedraleen
Partner - Creator II
Partner - Creator II
Author

Hi Team,
Below is qlikservice.js... Anyone who needs, can refer this.
I have connected to Qlik Engine and view all apps, sheets and its object details. Used gethypercubedata method for extracting data from charts. To extract from Filterpane listboxes, used GetListObjectData method.

const enigma = require('enigma.js');
const WebSocket = require('ws');
const schema = require('enigma.js/schemas/12.170.2.json');

const QLIK_HOST = process.env.QLIK_HOST || 'localhost:4848';

const createSession = (appId = null) => {
    const url = `ws://${QLIK_HOST}/app/${appId || ''}`;
    return enigma.create({
        schema,
        url,
        createSocket: (url) => new WebSocket(url),
    });
};

const getApps = async () => {
    const session = createSession();
    try {
        const global = await session.open();
        const docList = await global.getDocList();
        await session.close();
        return docList;
    } catch (err) {
        console.error('Error fetching apps:', err);
        throw err;
    }
};

const getAppStructure = async (appId) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);

        // Get Sheets
        const sheetListObject = await app.createSessionObject({
            qInfo: { qType: 'SheetList' },
            qAppObjectListDef: {
                qType: 'sheet',
                qData: { title: '/qMetaDef/title', description: '/qMetaDef/description' },
            },
        });

        const sheetLayout = await sheetListObject.getLayout();
        const sheets = sheetLayout.qAppObjectList.qItems.map(item => ({
            id: item.qInfo.qId,
            title: item.qData.title,
        }));

        // For each sheet, list objects
        const structure = [];
        for (const sheet of sheets) {
            const sheetObj = await app.getObject(sheet.id);
            const sLayout = await sheetObj.getLayout();

            let objectIds = [];

            // Method 1: Get from ChildInfos
            const children = await sheetObj.getChildInfos();
            objectIds = children.map(c => c.qId);

            // Method 2: Get from cells (common for standard sheets)
            if (sLayout.cells && objectIds.length === 0) {
                objectIds = sLayout.cells.map(cell => cell.name);
            }

            const objects = [];
            for (const id of objectIds) {
                try {
                    const childObj = await app.getObject(id);
                    const childLayout = await childObj.getLayout();

                    // Try multiple paths for title
                    const title = childLayout.title ||
                        childLayout.qMetaDef?.title ||
                        (childLayout.showTitles && childLayout.title) ||
                        'Untitled Object';

                    objects.push({
                        id: id,
                        type: childLayout.qInfo.qType,
                        title: title,
                    });
                } catch (childErr) {
                    console.warn(`Could not fetch details for object ${id}:`, childErr.message);
                }
            }

            structure.push({
                ...sheet,
                objects
            });
        }

        await session.close();
        return structure;
    } catch (err) {
        console.error(`Error fetching structure for app ${appId}:`, err);
        if (session) await session.close();
        throw err;
    }
};

const getObjectData = async (appId, objectId) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);
        const obj = await app.getObject(objectId);
        const layout = await obj.getLayout();

        if (!layout.qHyperCube) {
            throw new Error('Object does not contain a HyperCube');
        }

        const hc = layout.qHyperCube;
        const headers = [
            ...hc.qDimensionInfo.map(d => ({ label: d.qFallbackTitle, type: 'dimension' })),
            ...hc.qMeasureInfo.map(m => ({ label: m.qFallbackTitle, type: 'measure' }))
        ];

        // Fetch data (simple paging for first 100 rows, can be expanded)
        const qPage = [{ qTop: 0, qLeft: 0, qHeight: 100, qWidth: headers.length }];
        const dataPages = await obj.getHyperCubeData('/qHyperCubeDef', qPage);

        const rows = dataPages[0].qMatrix.map(row => {
            return row.map(cell => cell.qText || cell.qNum);
        });

        await session.close();
        return { headers, rows, title: layout.title || 'Data' };
    } catch (err) {
        console.error(`Error fetching data for object ${objectId} in app ${appId}:`, err);
        if (session) await session.close();
        throw err;
    }
};

const getStudentFilters = async (appId, selections = {}) => {
    const session = createSession(appId);
    try {
        const global = await session.open();
        const app = await global.openDoc(appId);

        // Map UI keys to Qlik Field Names
        const fieldMap = {
            Company: 'Company',
            Branch: 'Branch',
            StudentID: 'Student_ID',
            StudentName: 'Student Name'
        };

        // Apply existing selections to the app session
        for (const [key, values] of Object.entries(selections)) {
            if (values && values.length > 0) {
                try {
                    const fieldName = fieldMap[key];
                    const qField = await app.getField(fieldName);
                    // Convert values to Qlik selection format
                    const qValues = values.map(v => ({ qText: v.toString() }));
                    await qField.selectValues(qValues, false); // false = replace existing selections in this session
                } catch (selectErr) {
                    console.warn(`Could not apply selection for ${key}:`, selectErr.message);
                }
            }
        }

        const listboxMap = {
            Company: '1ab18293-be8e-497e-9d32-84aaa708375d',
            Branch: '2b04e7a7-919a-4696-9e9b-8bc323251739',
            StudentID: '2d864310-d740-473a-bb09-24d97ce3dcd0',
            StudentName: 'af924ba2-a043-46e3-a5e5-3dcfff4d44ab'
        };


        const result = {};

        for (const [key, id] of Object.entries(listboxMap)) {
            console.log(`Fetching data for filter: ${key} (ID: ${id})`);
            try {
                const obj = await app.getObject(id);
                const layout = await obj.getLayout();

                if (!layout.qListObject) {
                    console.warn(`Object ${id} is not a Listbox or has no qListObject property.`);
                    result[key] = [];
                    continue;
                }

                const totalRows = layout.qListObject.qSize.qcy;
                const items = [];
                const pageSize = 10000;

                for (let top = 0; top < totalRows; top += pageSize) {
                    const pages = [{ qTop: top, qLeft: 0, qHeight: pageSize, qWidth: 1 }];
                    const data = await obj.getListObjectData('/qListObjectDef', pages);

                    if (data && data[0] && data[0].qMatrix) {
                        data[0].qMatrix.forEach(row => {
                            if (row[0]) {
                                // Only add if Selected (S) or Optional/Possible (O)
                                // Standard Qlik states: S=Selected, O=Optional, X=Excluded, A=Alternative
                                const state = row[0].qState;
                                if (state === 'S' || state === 'O') {
                                    let val = row[0].qText || row[0].qNum;
                                    if (val !== undefined && val !== null && val !== '') {
                                        val = val.toString();
                                        if (key === 'StudentName') val = val.toUpperCase();
                                        items.push(val);
                                    }
                                }

                            }
                        });
                    }

                }
                result[key] = items.sort();
                console.log(`Found ${items.length} unique values for ${key}`);
            } catch (objErr) {
                console.error(`Error fetching listbox ${id}:`, objErr.message);
                result[key] = [];
            }
        }

        await session.close();
        return result;
    } catch (err) {
        console.error('Error fetching student filters via listboxes:', err);
        if (session) await session.close();
        throw err;
    }
};


module.exports = {
    getApps,
    getAppStructure,
    getObjectData,
    getStudentFilters
};