{"id":10232,"date":"2026-08-15T00:13:10","date_gmt":"2026-08-14T22:13:10","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/ga4-channel-grouping-debugger\/"},"modified":"2026-10-20T15:01:43","modified_gmt":"2026-10-20T13:01:43","slug":"ga4-channel-grouping-debugger","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/","title":{"rendered":"GA4 Channel Grouping &#038; Unassigned Debugger"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">GA4 walks eighteen rules from top to bottom and takes the first one that matches. This tool runs the same chain on a landing page URL or on hand-typed values and marks the rule that decided the outcome.<\/p>\n<p>    <label for=\"cg-url\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Landing page URL (optional, fills the fields below)<\/label><br \/>\n    <input type=\"text\" id=\"cg-url\" class=\"form-control\" style=\"width: 100%; padding: 12px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; font-size: 0.85rem; box-sizing: border-box;\" placeholder=\"https:\/\/example.com\/page?utm_source=newsletter&amp;utm_medium=email\"><\/p>\n<div style=\"display: flex; gap: 12px; flex-wrap: wrap; margin-top: 15px;\">\n<div style=\"flex: 1; min-width: 170px;\">\n            <label for=\"cg-quelle\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">utm_source<\/label><br \/>\n            <input type=\"text\" id=\"cg-quelle\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" placeholder=\"google\">\n        <\/div>\n<div style=\"flex: 1; min-width: 170px;\">\n            <label for=\"cg-medium\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">utm_medium<\/label><br \/>\n            <input type=\"text\" id=\"cg-medium\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" placeholder=\"cpc\">\n        <\/div>\n<div style=\"flex: 1; min-width: 170px;\">\n            <label for=\"cg-kampagne\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">utm_campaign<\/label><br \/>\n            <input type=\"text\" id=\"cg-kampagne\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" placeholder=\"summer_sale\">\n        <\/div>\n<div style=\"flex: 1; min-width: 200px;\">\n            <label for=\"cg-kategorie\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Source category<\/label><br \/>\n            <select id=\"cg-kategorie\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\"><option value=\"auto\">detect automatically<\/option><option value=\"none\">none or unknown source<\/option><option value=\"SEARCH\">search site<\/option><option value=\"SOCIAL\">social site<\/option><option value=\"VIDEO\">video site<\/option><option value=\"SHOPPING\">shopping site<\/option><\/select>\n        <\/div>\n<\/p><\/div>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap; margin: 18px 0 0;\">\n        <button id=\"cg-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Determine channel<\/button><br \/>\n        <button id=\"cg-beispiel\" class=\"button\" type=\"button\" style=\"background: transparent; color: var(--text-primary, #e8e8ee); border: 1px solid var(--border, #2a2a35); padding: 12px 20px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Load example<\/button>\n    <\/div>\n<div data-mp-mask id=\"cg-ergebnis\" style=\"margin-top: 22px;\"><\/div>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"GA4 walks eighteen rules from top to bottom and takes the first one that matches. This tool runs the same chain on a landing page URL or on hand-typed values and marks the rule that decided the outcome.\",\"label_url\":\"Landing page URL (optional, fills the fields below)\",\"ph_url\":\"https:\\\/\\\/example.com\\\/page?utm_source=newsletter\\u0026utm_medium=email\",\"label_quelle\":\"utm_source\",\"label_medium\":\"utm_medium\",\"label_kampagne\":\"utm_campaign\",\"label_kategorie\":\"Source category\",\"kat_auto\":\"detect automatically\",\"kat_keine\":\"none or unknown source\",\"kat_suche\":\"search site\",\"kat_social\":\"social site\",\"kat_video\":\"video site\",\"kat_shopping\":\"shopping site\",\"knopf\":\"Determine channel\",\"beispiel\":\"Load example\",\"fehler_url_leer\":\"No URL was entered.\",\"fehler_keine_parameter\":\"The URL carries no query string, so there is nothing to read.\",\"ergebnis_kopf\":\"Default channel group\",\"ergebnis_stelle\":\"Decided by rule %s - the first match wins, the rules below it are never evaluated.\",\"grund_unassigned\":\"Not one of the eighteen rules matched, so the session lands in Unassigned.\",\"h_werte\":\"Values used\",\"h_hinweise\":\"Findings\",\"h_regeln\":\"Rule chain\",\"regeln_erklaerung\":\"Plus marks a rule that matches. The highlighted row is the one GA4 stops at.\",\"l_kategorie\":\"Source category\",\"r_direct\":\"Source is (direct) and medium is (none) or (not set).\",\"r_crossnetwork\":\"The campaign name contains cross-network.\",\"r_paidshopping\":\"Source is a shopping site or the campaign name looks like shopping, and the medium is a paid one.\",\"r_paidsearch\":\"Source is a search site and the medium is a paid one.\",\"r_paidsocial\":\"Source is a social site and the medium is a paid one.\",\"r_paidvideo\":\"Source is a video site and the medium is a paid one.\",\"r_display\":\"Medium is display, banner, expandable, interstitial or cpm.\",\"r_paidother\":\"The medium matches the paid pattern: anything containing cp, plus ppc, retargeting and everything starting with paid.\",\"r_orgshopping\":\"Source is a shopping site or the campaign name looks like shopping.\",\"r_orgsocial\":\"Source is a social site or the medium is social, social-network, social-media or sm.\",\"r_orgvideo\":\"Source is a video site or the medium contains video.\",\"r_orgsearch\":\"Source is a search site or the medium is organic.\",\"r_referral\":\"Medium is referral, app or link.\",\"r_email\":\"Source or medium is email, e-mail, e_mail or e mail.\",\"r_affiliate\":\"Medium is affiliate.\",\"r_audio\":\"Medium is audio.\",\"r_sms\":\"Source or medium is sms.\",\"r_push\":\"Medium ends in push or contains mobile or notification, or the source is firebase.\",\"h_gclid\":\"gclid, gbraid or wbraid is present: with auto-tagging switched on GA4 derives google \\\/ cpc even without utm parameters.\",\"h_msclkid\":\"msclkid is present: auto-tagging in Microsoft Advertising leads to bing \\\/ cpc.\",\"h_fbclid\":\"fbclid is only a click identifier of Meta. GA4 derives no source from it, so the session stays a referral from facebook.com or falls back to direct.\",\"h_utmid\":\"utm_id without utm_source: the identifier alone creates no source and never reaches the channel grouping.\",\"h_leerzeichen\":\"%s carries a leading or trailing space, which becomes part of the stored value.\",\"h_grossbuchstaben\":\"%s contains capital letters. GA4 stores them unchanged, so Email and email end up as two separate rows.\",\"h_medium_fehlt\":\"utm_medium is missing while utm_source is set. That is the most frequent cause of Unassigned.\",\"h_quelle_fehlt\":\"utm_source is missing. Without a source the medium alone rarely produces a channel.\",\"h_tippfehler\":\"The medium %s is not a value GA4 recognises, which usually means a typing error.\",\"hinweis_namen\":\"Channel names appear as the Data API and the BigQuery export return them. The GA4 interface translates them into the report language. The source categories held here are an excerpt of the list Google publishes - for a source that is missing, the category can be set by hand.\"};<\/p>\n<p>    \/\/ --- reine Auswertung, ohne Zugriff auf das Dokument ---<\/p>\n<p>    \/\/ Auszug aus den Quellkategorien von Google. Die vollstaendige Liste hat\n    \/\/ ueber tausend Eintraege; wer eine fehlende Quelle pruefen will, stellt\n    \/\/ die Kategorie von Hand ein.\n    const KATEGORIEN = {\n        SEARCH: ['google', 'bing', 'yahoo', 'duckduckgo', 'baidu', 'yandex', 'ecosia', 'ask',\n            'aol', 'brave', 'startpage', 'seznam', 'naver', 'qwant', 'sogou', 'msn', 'lycos',\n            'search.google.com', 'google.com', 'bing.com', 'duckduckgo.com', 'yandex.ru'],\n        SOCIAL: ['facebook', 'instagram', 'twitter', 't.co', 'linkedin', 'pinterest', 'reddit',\n            'tiktok', 'snapchat', 'vk.com', 'weibo', 'quora', 'tumblr', 'threads', 'xing',\n            'facebook.com', 'instagram.com', 'linkedin.com', 'l.facebook.com', 'lm.facebook.com',\n            'm.facebook.com', 'pinterest.com', 'tiktok.com', 'reddit.com'],\n        VIDEO: ['youtube', 'vimeo', 'dailymotion', 'twitch', 'youtube.com', 'm.youtube.com', 'vimeo.com', 'twitch.tv'],\n        SHOPPING: ['amazon', 'ebay', 'etsy', 'alibaba', 'aliexpress', 'walmart', 'shopify',\n            'allegro', 'otto', 'amazon.com', 'amazon.de', 'ebay.com', 'ebay.de', 'etsy.com', 'allegro.pl']\n    };<\/p>\n<p>    \/\/ Die bezahlten Medien nach der Regel von Google: alles mit \"cp\" darin,\n    \/\/ dazu ppc, retargeting und alles, was mit paid beginnt.\n    const BEZAHLT = \/^(.*cp.*|ppc|retargeting|paid.*)$\/;\n    const EINKAUF_KAMPAGNE = \/^(.*(([^a-df-z]|^)shop|shopping).*)$\/;\n    const ANZEIGE = ['display', 'banner', 'expandable', 'interstitial', 'cpm'];\n    const SOZIAL_MEDIUM = ['social', 'social-network', 'social-media', 'sm', 'social network', 'social media'];\n    const EMPFEHLUNG = ['referral', 'app', 'link'];\n    const POST = ['email', 'e-mail', 'e_mail', 'e mail'];<\/p>\n<p>    function klein(wert) {\n        return String(wert === undefined || wert === null ? '' : wert).trim().toLowerCase();\n    }<\/p>\n<p>    function kategorieVon(quelle) {\n        const q = klein(quelle);\n        if (q === '') { return ''; }\n        const namen = Object.keys(KATEGORIEN);\n        for (let i = 0; i < namen.length; i++) {\n            const liste = KATEGORIEN[namen[i]];\n            for (let j = 0; j < liste.length; j++) {\n                const eintrag = liste[j];\n                \/\/ Treffer bei genauer Gleichheit oder wenn die Quelle den\n                \/\/ Namen als Wortbestandteil einer Domain traegt.\n                if (q === eintrag || q === eintrag + '.com' || q.indexOf(eintrag + '.') === 0 || q.indexOf('.' + eintrag + '.') !== -1) {\n                    return namen[i];\n                }\n            }\n        }\n        return '';\n    }\n\n    \/**\n     * Die Reihenfolge ist die eigentliche Aussage: GA4 nimmt die erste Regel,\n     * die zutrifft, und hoert dann auf. Deshalb steht hier jede Regel als\n     * eigener Eintrag mit ihrer Bedingung.\n     *\/\n    function regeln(quelle, medium, kampagne, kategorie) {\n        const q = klein(quelle);\n        const m = klein(medium);\n        const k = klein(kampagne);\n        const kat = kategorie || kategorieVon(q);\n        const bezahlt = BEZAHLT.test(m);\n\n        return [\n            { name: 'Direct', bedingung: T.r_direct,\n              trifft: (q === '(direct)' || q === 'direct' || q === '') &#038;&#038; (m === '(none)' || m === '(not set)' || m === 'none' || m === '') },\n            { name: 'Cross-network', bedingung: T.r_crossnetwork,\n              trifft: k.indexOf('cross-network') !== -1 },\n            { name: 'Paid Shopping', bedingung: T.r_paidshopping,\n              trifft: (kat === 'SHOPPING' || EINKAUF_KAMPAGNE.test(k)) &#038;&#038; bezahlt },\n            { name: 'Paid Search', bedingung: T.r_paidsearch,\n              trifft: kat === 'SEARCH' &#038;&#038; bezahlt },\n            { name: 'Paid Social', bedingung: T.r_paidsocial,\n              trifft: kat === 'SOCIAL' &#038;&#038; bezahlt },\n            { name: 'Paid Video', bedingung: T.r_paidvideo,\n              trifft: kat === 'VIDEO' &#038;&#038; bezahlt },\n            { name: 'Display', bedingung: T.r_display,\n              trifft: ANZEIGE.indexOf(m) !== -1 },\n            { name: 'Paid Other', bedingung: T.r_paidother,\n              trifft: bezahlt },\n            { name: 'Organic Shopping', bedingung: T.r_orgshopping,\n              trifft: kat === 'SHOPPING' || EINKAUF_KAMPAGNE.test(k) },\n            { name: 'Organic Social', bedingung: T.r_orgsocial,\n              trifft: kat === 'SOCIAL' || SOZIAL_MEDIUM.indexOf(m) !== -1 },\n            { name: 'Organic Video', bedingung: T.r_orgvideo,\n              trifft: kat === 'VIDEO' || \/video\/.test(m) },\n            { name: 'Organic Search', bedingung: T.r_orgsearch,\n              trifft: kat === 'SEARCH' || m === 'organic' },\n            { name: 'Referral', bedingung: T.r_referral,\n              trifft: EMPFEHLUNG.indexOf(m) !== -1 },\n            { name: 'Email', bedingung: T.r_email,\n              trifft: POST.indexOf(q) !== -1 || POST.indexOf(m) !== -1 },\n            { name: 'Affiliates', bedingung: T.r_affiliate,\n              trifft: m === 'affiliate' },\n            { name: 'Audio', bedingung: T.r_audio,\n              trifft: m === 'audio' },\n            { name: 'SMS', bedingung: T.r_sms,\n              trifft: q === 'sms' || m === 'sms' },\n            { name: 'Mobile Push Notifications', bedingung: T.r_push,\n              trifft: m.length >= 4 && m.slice(-4) === 'push' || m.indexOf('mobile') !== -1 || m.indexOf('notification') !== -1 || q === 'firebase' }\n        ];\n    }<\/p>\n<p>    function ausUrl(url) {\n        const raus = { ok: false, fehler: '', parameter: {}, quelle: '', medium: '', kampagne: '', hinweise: [] };\n        const roh = String(url === undefined || url === null ? '' : url).trim();\n        if (roh === '') { raus.fehler = T.fehler_url_leer; return raus; }<\/p>\n<p>        let abfrage = '';\n        const fragezeichen = roh.indexOf('?');\n        if (fragezeichen !== -1) {\n            abfrage = roh.slice(fragezeichen + 1);\n            const raute = abfrage.indexOf('#');\n            if (raute !== -1) { abfrage = abfrage.slice(0, raute); }\n        }\n        if (abfrage === '') { raus.fehler = T.fehler_keine_parameter; return raus; }<\/p>\n<p>        abfrage.split('&').forEach(function (paar) {\n            if (paar === '') { return; }\n            const teil = paar.split('=');\n            const name = decodeURIComponent(teil[0].replace(\/\\+\/g, ' '));\n            const wert = teil.length > 1 ? decodeURIComponent(teil.slice(1).join('=').replace(\/\\+\/g, ' ')) : '';\n            raus.parameter[name] = wert;\n        });<\/p>\n<p>        const p = raus.parameter;\n        raus.quelle = p.utm_source || '';\n        raus.medium = p.utm_medium || '';\n        raus.kampagne = p.utm_campaign || '';<\/p>\n<p>        \/\/ Automatische Kennzeichnung: die Klickkennungen setzen Quelle und\n        \/\/ Medium, ohne dass utm-Parameter noetig waeren.\n        if (!raus.quelle && (p.gclid || p.gbraid || p.wbraid)) {\n            raus.quelle = 'google';\n            raus.medium = raus.medium || 'cpc';\n            raus.hinweise.push(T.h_gclid);\n        }\n        if (!raus.quelle && p.msclkid) {\n            raus.quelle = 'bing';\n            raus.medium = raus.medium || 'cpc';\n            raus.hinweise.push(T.h_msclkid);\n        }\n        if (p.fbclid && !p.utm_source) {\n            raus.hinweise.push(T.h_fbclid);\n        }\n        if (p.utm_id && !p.utm_source) {\n            raus.hinweise.push(T.h_utmid);\n        }\n        raus.ok = true;\n        return raus;\n    }<\/p>\n<p>    function pruefeWerte(quelle, medium, kampagne) {\n        const hinweise = [];\n        const roh = { quelle: String(quelle || ''), medium: String(medium || ''), kampagne: String(kampagne || '') };<\/p>\n<p>        Object.keys(roh).forEach(function (feld) {\n            const wert = roh[feld];\n            if (wert !== wert.trim()) {\n                hinweise.push(T.h_leerzeichen.replace('%s', feld === 'quelle' ? 'utm_source' : (feld === 'medium' ? 'utm_medium' : 'utm_campaign')));\n            }\n            if (wert.trim() !== '' && wert !== wert.toLowerCase()) {\n                hinweise.push(T.h_grossbuchstaben.replace('%s', feld === 'quelle' ? 'utm_source' : (feld === 'medium' ? 'utm_medium' : 'utm_campaign')));\n            }\n        });<\/p>\n<p>        const q = klein(quelle);\n        const m = klein(medium);\n        if (q !== '' && m === '') { hinweise.push(T.h_medium_fehlt); }\n        if (q === '' && m !== '') { hinweise.push(T.h_quelle_fehlt); }\n        if (m === 'referal' || m === 'referrer') { hinweise.push(T.h_tippfehler.replace('%s', m)); }\n        if (m === 'cpc ' || m === 'ppc.') { hinweise.push(T.h_tippfehler.replace('%s', m)); }\n        if (m === 'social' && q === '') { hinweise.push(T.h_quelle_fehlt); }\n        if (m === 'email' && q === '') { hinweise.push(T.h_quelle_fehlt); }\n        return hinweise;\n    }<\/p>\n<p>    function bestimmen(quelle, medium, kampagne, kategorie) {\n        const liste = regeln(quelle, medium, kampagne, kategorie === 'auto' || !kategorie ? '' : (kategorie === 'none' ? 'KEINE' : kategorie));\n        let kanal = 'Unassigned';\n        let grund = T.grund_unassigned;\n        let stelle = -1;\n        for (let i = 0; i < liste.length; i++) {\n            if (liste[i].trifft) {\n                kanal = liste[i].name;\n                grund = liste[i].bedingung;\n                stelle = i;\n                break;\n            }\n        }\n        return {\n            kanal: kanal,\n            grund: grund,\n            stelle: stelle,\n            regeln: liste,\n            kategorie: kategorie === 'auto' || !kategorie ? kategorieVon(quelle) : (kategorie === 'none' ? '' : kategorie),\n            hinweise: pruefeWerte(quelle, medium, kampagne)\n        };\n    }\n\n    if (typeof window !== 'undefined') {\n        window.LW_TEST = window.LW_TEST || {};\n        window.LW_TEST.CG = {\n            bestimmen: bestimmen,\n            ausUrl: ausUrl,\n            kategorieVon: kategorieVon,\n            regeln: regeln\n        };\n    }\n\n    \/\/ --- Anbindung an das Dokument ---\n\n    const btn = document.getElementById('cg-btn');\n    const out = document.getElementById('cg-ergebnis');\n    const urlFeld = document.getElementById('cg-url');\n    const quelleFeld = document.getElementById('cg-quelle');\n    const mediumFeld = document.getElementById('cg-medium');\n    const kampagneFeld = document.getElementById('cg-kampagne');\n    const katFeld = document.getElementById('cg-kategorie');\n    const beispielBtn = document.getElementById('cg-beispiel');\n    if (!btn || !out || !urlFeld || !quelleFeld || !mediumFeld || !kampagneFeld || !katFeld || !beispielBtn) { return; }\n\n    const KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 14px; margin-bottom: 18px;';\n    const UEBERSCHRIFT = 'color: var(--text-primary, #e8e8ee); font-weight: 700; margin-bottom: 8px;';\n\n    function el(tag, css, text) {\n        const knoten = document.createElement(tag);\n        if (css) { knoten.setAttribute('style', css); }\n        if (text !== undefined &#038;&#038; text !== null) { knoten.textContent = text; }\n        return knoten;\n    }\n\n    function zeile(kasten, name, wert) {\n        const z = el('div', 'display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding: 5px 0;');\n        z.appendChild(el('span', 'color: var(--text-secondary, #a0a0b0);', name));\n        z.appendChild(el('span', 'color: var(--text-primary, #e8e8ee); font-family: monospace; text-align: right; word-break: break-all;', wert));\n        kasten.appendChild(z);\n    }\n\n    function zeigen(erg, quelle, medium, kampagne) {\n        out.textContent = '';\n\n        const treffer = erg.kanal !== 'Unassigned';\n        const kopf = el('div', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left: 3px solid ' + (treffer ? 'var(--accent, #7ee787)' : '#ffb86c') + '; border-radius: 6px; padding: 18px; margin-bottom: 18px;');\n        kopf.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.85rem;', T.ergebnis_kopf));\n        kopf.appendChild(el('div', 'color: ' + (treffer ? 'var(--accent, #7ee787)' : '#ffb86c') + '; font-size: 1.5rem; font-weight: 700; font-family: monospace; margin: 4px 0 8px;', erg.kanal));\n        kopf.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.9rem;', erg.grund));\n        if (erg.stelle >= 0) {\n            kopf.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.85rem; margin-top: 6px;', T.ergebnis_stelle.replace('%s', String(erg.stelle + 1))));\n        }\n        out.appendChild(kopf);<\/p>\n<p>        out.appendChild(el('div', UEBERSCHRIFT, T.h_werte));\n        const werte = el('div', KASTEN);\n        zeile(werte, 'utm_source', quelle === '' ? '(not set)' : quelle);\n        zeile(werte, 'utm_medium', medium === '' ? '(not set)' : medium);\n        zeile(werte, 'utm_campaign', kampagne === '' ? '(not set)' : kampagne);\n        zeile(werte, T.l_kategorie, erg.kategorie === '' ? T.kat_keine : erg.kategorie);\n        out.appendChild(werte);<\/p>\n<p>        if (erg.hinweise.length) {\n            out.appendChild(el('div', UEBERSCHRIFT, T.h_hinweise));\n            const kasten = el('div', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left: 3px solid #ffb86c; border-radius: 6px; padding: 14px; margin-bottom: 18px;');\n            erg.hinweise.forEach(function (h) {\n                kasten.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); padding: 4px 0; font-size: 0.9rem;', h));\n            });\n            out.appendChild(kasten);\n        }<\/p>\n<p>        out.appendChild(el('div', UEBERSCHRIFT, T.h_regeln));\n        out.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.85rem; margin-bottom: 10px;', T.regeln_erklaerung));\n        const tabelle = el('div', KASTEN);\n        erg.regeln.forEach(function (r, i) {\n            const genommen = i === erg.stelle;\n            const z = el('div', 'display: flex; gap: 12px; align-items: flex-start; padding: 7px 0; border-bottom: 1px solid var(--border, #2a2a35);' + (genommen ? ' background: rgba(126, 231, 135, 0.07);' : ''));\n            z.appendChild(el('span', 'width: 26px; color: var(--text-secondary, #a0a0b0); font-family: monospace; font-size: 0.8rem;', String(i + 1)));\n            z.appendChild(el('span', 'width: 22px; color: ' + (r.trifft ? 'var(--accent, #7ee787)' : 'var(--text-secondary, #a0a0b0)') + '; font-family: monospace;', r.trifft ? '+' : '-'));\n            const text = el('span', 'flex: 1;');\n            text.appendChild(el('div', 'color: ' + (genommen ? 'var(--accent, #7ee787)' : 'var(--text-primary, #e8e8ee)') + '; font-weight: ' + (genommen ? '700' : '400') + '; font-family: monospace; font-size: 0.88rem;', r.name));\n            text.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; line-height: 1.5;', r.bedingung));\n            z.appendChild(text);\n            tabelle.appendChild(z);\n        });\n        out.appendChild(tabelle);<\/p>\n<p>        out.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.85rem;', T.hinweis_namen));\n    }<\/p>\n<p>    function auswerten() {\n        let quelle = quelleFeld.value;\n        let medium = mediumFeld.value;\n        let kampagne = kampagneFeld.value;\n        let zusatz = [];<\/p>\n<p>        if (urlFeld.value.trim() !== '') {\n            const zerlegt = ausUrl(urlFeld.value);\n            if (!zerlegt.ok) {\n                out.textContent = '';\n                out.appendChild(el('div', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left: 3px solid var(--accent, #7ee787); color: var(--text-secondary, #a0a0b0); padding: 14px; border-radius: 6px;', zerlegt.fehler));\n                return;\n            }\n            quelle = zerlegt.quelle;\n            medium = zerlegt.medium;\n            kampagne = zerlegt.kampagne;\n            quelleFeld.value = quelle;\n            mediumFeld.value = medium;\n            kampagneFeld.value = kampagne;\n            zusatz = zerlegt.hinweise;\n        }<\/p>\n<p>        const erg = bestimmen(quelle, medium, kampagne, katFeld.value);\n        erg.hinweise = zusatz.concat(erg.hinweise);\n        zeigen(erg, quelle, medium, kampagne);\n    }<\/p>\n<p>    btn.addEventListener('click', auswerten);<\/p>\n<p>    beispielBtn.addEventListener('click', function () {\n        urlFeld.value = 'https:\/\/www.example.com\/landing?utm_source=newsletter&utm_campaign=august';\n        quelleFeld.value = '';\n        mediumFeld.value = '';\n        kampagneFeld.value = '';\n        katFeld.value = 'auto';\n        auswerten();\n    });\n})();\n<\/script><\/p>\n<p><!-- lw-analytics-acquisition:start -->\n<link rel=\"stylesheet\" href=\"\/blog\/wp-content\/themes\/lw-theme\/js\/analytics-workbench.css?v=20260927a\">\n<h2>Live Acquisition Audit<\/h2>\n<p>Inspect the actual session sources, mediums, campaigns and channel groups reported by GA4. The audit highlights Unassigned rows and spelling variants. The existing channel-rule checker above remains available for individual examples.<\/p>\n<div id=\"lw-analytics-workbench\" data-kind=\"acquisition\" data-rc-private data-mp-mask><\/div>\n<p><script type=\"application\/json\" id=\"lw-analytics-config\">{\"client\": \"Public OAuth Web client ID\", \"quota\": \"Quota project ID (optional)\", \"loadLogin\": \"Load Google login\", \"login\": \"Sign in with Google\", \"disconnect\": \"Disconnect and clear\", \"clear\": \"Clear local data\", \"cancel\": \"Cancel\", \"loading\": \"Loading\u2026\", \"done\": \"Completed.\", \"loginReady\": \"Login loaded. Click Sign in with Google.\", \"loginWaiting\": \"Waiting for Google. Allow popups or use a regular browser tab.\", \"connected\": \"Connected with read-only access.\", \"disconnected\": \"Local results cleared; Google permission remains until revoked in the Google account.\", \"popup\": \"Google login was closed or blocked.\", \"authError\": \"Login missing, expired or permission not granted.\", \"clientInvalid\": \"A Web application client ID is required, not a project ID or secret.\", \"setupTitle\": \"OAuth setup and limits\", \"setup\": \"The prefilled client can be replaced. An own Web application client requires https:\/\/www.lukaswojcik.com as an authorized JavaScript origin, the Analytics Data API and Admin API, a configured consent screen and any required test-user or verification setup. Only analytics.readonly is requested. No cloud-platform permission, client secret or AI service is used. API access remains subject to Google permissions and quotas. Cancellation stops waiting locally; an accepted Google request may still run.\", \"privacyOAuth\": \"Login loads on click. Tokens and results stay in tab memory; API calls go directly to Google. No report data or tokens go to this website\u2019s server. Tracking, session replay and chat are disabled on this tool page. Normal page-access logs remain. Saving a snapshot or CSV creates a local download.\", \"property\": \"Numeric GA4 property ID\", \"start\": \"Start date\", \"end\": \"End date\", \"loadProperties\": \"Load properties\", \"choose\": \"Choose\u2026\", \"demo\": \"Try invented example\", \"demoTitle\": \"Invented example\", \"demoNotice\": \"Example data only. No Google request was sent.\", \"auditRun\": \"Audit acquisition data\", \"auditSummary\": \"Sum of reported session values\", \"auditLimits\": \"The percentage uses the sum of the returned rows, not a separate property total. Up to 50,000 rows; incomplete pagination is rejected. Sampling, thresholding and (other) can hide detail: inspect the metadata. Case and whitespace variants are review candidates, not proof of a tracking error. (not set) alone does not prove missing consent or lost UTMs. No historical data is changed.\", \"source\": \"Source\", \"medium\": \"Medium\", \"campaign\": \"Campaign\", \"channel\": \"Channel\", \"sessions\": \"Sessions\", \"findings\": \"Review flags\", \"noFlag\": \"No rule matched\", \"unassigned\": \"Unassigned channel\", \"notSet\": \"Contains (not set)\", \"other\": \"Aggregated (other) row\", \"variant0\": \"Source variants\", \"variant1\": \"Medium variants\", \"variant2\": \"Campaign variants\", \"spaces0\": \"Source whitespace\", \"spaces1\": \"Medium whitespace\", \"spaces2\": \"Campaign whitespace\", \"metadata\": \"API metadata and quota\", \"export\": \"Download full comparison CSV\", \"previewLimit\": \"Preview limited to 500 rows; download contains all rows.\", \"snapshotA\": \"Snapshot A \u00b7 before \/ reference\", \"snapshotB\": \"Snapshot B \u00b7 after \/ comparison\", \"capture\": \"Read configuration\", \"saveSnapshot\": \"Save snapshot JSON\", \"loadSnapshot\": \"Load local snapshot JSON\", \"needSnapshots\": \"Two valid snapshots are required.\", \"compare\": \"Compare\", \"differences\": \"Different fields\", \"setting\": \"Setting\", \"before\": \"A \u00b7 before\", \"after\": \"B \u00b7 after\", \"status\": \"Status\", \"added\": \"Added\", \"removed\": \"Removed\", \"changed\": \"Changed\", \"configScope\": \"Compare two properties or two saved points in time. Coverage: property name, timezone, currency, industry and service level; event retention; stream names, types and website\/app identifiers; custom dimensions\/metrics; key events. No API secrets are requested or exported.\", \"configLimits\": \"A snapshot covers only the listed fields and is not a full backup or change history. Resource IDs, creation times and measurement IDs are excluded. Streams are matched by type and name, custom definitions by scope and parameter, key events by event name. Renaming a matching key appears as removal plus addition. Failed API reads do not produce a partial snapshot. Zero differences apply only to this scope.\", \"privacyCSV\": \"Files are read only in this browser, without login or upload. No CSV data goes to Google or this website\u2019s server. Tracking, session replay and chat are disabled here; normal page-access logs remain. Downloads are local files.\", \"csvContract\": \"Each file needs one row per order, an order ID, an amount and a three-letter currency code. Up to 5 MB and 20,000 data rows per file. Choose delimiter and decimal mark separately for each file. No thousands separators. IDs remain exact text, including leading zeros; surrounding whitespace is rejected. Amounts use exact decimal arithmetic.\", \"delimiter\": \"Field separator\", \"decimal\": \"Decimal mark in this file\", \"precision\": \"Decimal places (0, 2 or 3)\", \"tolerance\": \"Tolerance per order (dot decimal)\", \"comma\": \"Comma\", \"semicolon\": \"Semicolon\", \"shopFile\": \"Shop CSV\", \"analyticsFile\": \"Analytics CSV\", \"csvFile\": \"Local CSV file\", \"orderId\": \"Order ID\", \"amount\": \"Amount\", \"currency\": \"Currency\", \"rows\": \"data rows\", \"confirmBasis\": \"Both files use the same period, timezone and amount definition (tax, shipping, refunds). One row represents one order.\", \"csvLimits\": \"Duplicates are flagged, never silently added together. A currency mismatch is not converted. Negative amounts are allowed but must follow the agreed refund definition; this tool cannot infer it. Missing orders do not by themselves prove broken tracking. Delta = Analytics minus shop. Equal means equal within the selected tolerance; it is not an audit of completeness. Exported CSV cells are protected against spreadsheet formulas.\", \"results\": \"Results\", \"shop\": \"Shop amount\", \"analytics\": \"Analytics amount\", \"shopCurrency\": \"Shop currency\", \"analyticsCurrency\": \"Analytics currency\", \"delta\": \"Difference\", \"shopRows\": \"Shop rows\", \"analyticsRows\": \"Analytics rows\", \"equal\": \"Equal within tolerance\", \"different\": \"Amount differs\", \"duplicate\": \"Duplicate ID\", \"shopOnly\": \"Only in shop\", \"analyticsOnly\": \"Only in Analytics\", \"currencyMismatch\": \"Currency differs\", \"reloadCSV\": \"Separator changed; reload this CSV file.\", \"cancelled\": \"Cancelled or timed out. No automatic retry.\", \"error\": \"Could not process the data. Check file format, permissions and API availability.\", \"errors\": {\"date\": \"Use valid dates with start no later than end.\", \"property\": \"Use a numeric property ID, not a G- measurement ID.\", \"schema\": \"Unexpected or incomplete response schema. No result produced.\", \"duplicate\": \"Duplicate matching keys; no reliable comparison is possible.\", \"number\": \"Invalid number, excessive decimals or thousands separators. Tolerance uses a dot.\", \"snapshot\": \"Invalid snapshot format, unknown version or ambiguous keys.\", \"limit\": \"Row limit exceeded or pagination changed. No partial result is presented.\", \"size\": \"File exceeds 5 MB, 20,000 CSV rows or 100 columns.\", \"csv\": \"Invalid CSV: check separator, quoting, unique headers and column counts.\", \"empty\": \"No data rows found.\", \"mapping\": \"Assign three different columns per file.\", \"id\": \"Missing\/reserved ID, surrounding whitespace or invalid currency code.\", \"files\": \"Load both CSV files first.\", \"basis\": \"Confirm the common comparison basis first.\", \"needSnapshots\": \"Two valid snapshots are required.\", \"auth\": \"Login missing, expired or permission not granted.\", \"sdk\": \"Google login could not be loaded.\", \"quota\": \"Invalid quota project ID.\", \"http400\": \"Google rejected the request (400). Check dimensions, property and dates.\", \"http401\": \"Login missing, expired or permission not granted.\", \"http403\": \"Google denied access (403). Check enabled APIs, property permissions and quota project. A failed configuration section aborts the snapshot.\", \"http429\": \"Google quota exceeded (429). Retry later.\"}, \"cleared\": \"Local files, mappings and results cleared.\"}<\/script><script src=\"\/blog\/wp-content\/themes\/lw-theme\/js\/analytics-workbench-core.js?v=20260927a\"><\/script><script src=\"\/blog\/wp-content\/themes\/lw-theme\/js\/analytics-workbench-ui.js?v=20261020\"><\/script><\/p>\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\" target=\"_blank\" rel=\"noopener noreferrer\">Google: dimensions and metrics<\/a><\/li>\n<li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/rest\/v1beta\/ResponseMetaData\" target=\"_blank\" rel=\"noopener noreferrer\">Google: report metadata<\/a><\/li>\n<\/ul>\n<p><section class=\"aw-reading\"><h2>Practical articles<\/h2><ul><li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/grouping-ga4-visits-by-origin-understanding-sources-media-and-channel-rules\/\">Grouping GA4 Visits by Origin: Understanding Sources, Media and Channel Rules<\/a><\/li><li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/unassigned-visits-in-ga4-finding-and-fixing-missing-channel-attribution\/\">Unassigned Visits in GA4: Finding and Fixing Missing Channel Attribution<\/a><\/li><\/ul><\/section><br \/>\n<!-- lw-analytics-acquisition:end --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Shows which default channel group GA4 assigns to a source, medium and campaign, which of the eighteen rules matched, and why a session ends up in Unassigned.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":38,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[91297,91386,91258],"class_list":["post-10232","page","type-page","status-publish","hentry","tag-data-quality","tag-marketing-cyfrowy-pl","tag-google-analytics-4"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>GA4 Channel Grouping &amp; Unassigned Debugger | Lukas Wojcik<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"GA4 Channel Grouping &amp; Unassigned Debugger | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Shows which default channel group GA4 assigns to a source, medium and campaign, which of the eighteen rules matched, and why a session ends up in Unassigned.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-20T13:01:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/ga4-channel-grouping-debugger\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/ga4-channel-grouping-debugger\\\/\",\"name\":\"GA4 Channel Grouping & Unassigned Debugger | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-08-14T22:13:10+00:00\",\"dateModified\":\"2026-10-20T13:01:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/ga4-channel-grouping-debugger\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/ga4-channel-grouping-debugger\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/ga4-channel-grouping-debugger\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"GA4 Channel Grouping &amp; Unassigned Debugger\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"GA4 Channel Grouping & Unassigned Debugger | Lukas Wojcik","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/","og_locale":"en_US","og_type":"article","og_title":"GA4 Channel Grouping & Unassigned Debugger | Lukas Wojcik","og_description":"Shows which default channel group GA4 assigns to a source, medium and campaign, which of the eighteen rules matched, and why a session ends up in Unassigned.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-10-20T13:01:43+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/","name":"GA4 Channel Grouping & Unassigned Debugger | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-08-14T22:13:10+00:00","dateModified":"2026-10-20T13:01:43+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-channel-grouping-debugger\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/"},{"@type":"ListItem","position":3,"name":"GA4 Channel Grouping &amp; Unassigned Debugger"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10232","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=10232"}],"version-history":[{"count":5,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10232\/revisions"}],"predecessor-version":[{"id":20758,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10232\/revisions\/20758"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/38"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=10232"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=10232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}