{"id":9304,"date":"2026-08-09T15:37:09","date_gmt":"2026-08-09T13:37:09","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/ga4-bot-detector\/"},"modified":"2026-08-09T15:37:09","modified_gmt":"2026-08-09T13:37:09","slug":"ga4-bot-detector","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/","title":{"rendered":"Detektor bot\u00f3w GA4"},"content":{"rendered":"<p><script src=\"https:\/\/accounts.google.com\/gsi\/client\" async defer><\/script><\/p>\n<div class=\"ga4-bot-detector-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); margin-bottom: 20px; line-height: 1.6;\">\n        Po\u0142\u0105cz si\u0119 przez OAuth 2.0 bezpo\u015brednio z <strong>Google Analytics Data API v1<\/strong> i przeszukaj wymiary ruchu (system operacyjny, przegl\u0105darka, kraj, \u017ar\u00f3d\u0142o\/medium) pod k\u0105tem wzorc\u00f3w crawler\u00f3w, widmowego spamu oraz segment\u00f3w bot\u00f3w bez jakiegokolwiek zaanga\u017cowania.<br \/>\n        Wszystkie oceny heurystyczne wykonywane s\u0105 lokalnie w przegl\u0105darce &mdash; \u017cadne dane nie s\u0105 zapisywane ani przesy\u0142ane na nasze serwery.\n    <\/p>\n<p>    <!-- KROK 1: OAUTH I UWIERZYTELNIANIE --><\/p>\n<div style=\"background: var(--bg-body, #101416); padding: 20px; border-radius: 8px; border: 1px solid var(--border); margin-bottom: 20px;\">\n<h3 style=\"color: var(--accent); font-size: 1rem; margin-top: 0; margin-bottom: 12px;\">1. Uwierzytelnianie w Google Analytics API<\/h3>\n<div style=\"display: flex; gap: 15px; flex-wrap: wrap; align-items: flex-end;\">\n<div style=\"flex: 1; min-width: 280px;\">\n                <label style=\"color: var(--text-secondary); display: block; font-size: 0.85rem; margin-bottom: 6px;\">Identyfikator klienta OAuth Google Cloud:<\/label><br \/>\n                <input type=\"text\" id=\"ga4-client-id\" value=\"423029313598-2ko0jilc28eevp253rqncvodg2181e1l.apps.googleusercontent.com\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-panel); border: 1px solid var(--border); color: var(--text-primary); border-radius: 6px; font-family: monospace;\">\n            <\/div>\n<div>\n                <button id=\"ga4-auth-btn\" class=\"button\" style=\"background: var(--accent); color: #0b1114; border: none; padding: 11px 22px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Autoryzuj przez Google<\/button>\n            <\/div>\n<\/p><\/div>\n<div id=\"ga4-auth-status\" style=\"margin-top: 10px; font-size: 0.85rem; color: var(--text-secondary);\">Status: <strong style=\"color: #ff6b6b;\">Brak po\u0142\u0105czenia<\/strong><\/div>\n<\/p><\/div>\n<p>    <!-- KROK 2: KONFIGURACJA USLUGI I SKANOWANIA --><\/p>\n<div id=\"ga4-config-panel\" style=\"background: var(--bg-body); padding: 20px; border-radius: 8px; border: 1px solid var(--border); margin-bottom: 20px; display: none;\">\n<h3 style=\"color: var(--accent); font-size: 1rem; margin-top: 0; margin-bottom: 12px;\">2. Konfiguracja us\u0142ugi i skanowania bot\u00f3w<\/h3>\n<div style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 15px;\">\n<div>\n                <label style=\"color: var(--text-secondary); display: block; font-size: 0.85rem; margin-bottom: 6px;\">Identyfikator projektu GCP:<\/label><br \/>\n                <input type=\"text\" id=\"gcp-project-id\" value=\"lukaswojcik\" placeholder=\"lukaswojcik\" style=\"width: 100%; padding: 10px; background: var(--bg-panel); color: var(--text-primary); border: 1px solid var(--border); border-radius: 6px; font-family: monospace;\">\n            <\/div>\n<div>\n                <label style=\"color: var(--text-secondary); display: block; font-size: 0.85rem; margin-bottom: 6px;\">Identyfikator us\u0142ugi GA4 (numeryczny):<\/label><br \/>\n                <input type=\"text\" id=\"ga4-property-id\" placeholder=\"np. 345678901\" style=\"width: 100%; padding: 10px; background: var(--bg-panel); color: var(--text-primary); border: 1px solid var(--border); border-radius: 6px; font-family: monospace;\">\n            <\/div>\n<div>\n                <label style=\"color: var(--text-secondary); display: block; font-size: 0.85rem; margin-bottom: 6px;\">Zakres czasu:<\/label><br \/>\n                <select id=\"ga4-timeframe\" style=\"width: 100%; padding: 10px; background: var(--bg-panel); color: var(--text-primary); border: 1px solid var(--border); border-radius: 6px;\"><option value=\"14daysAgo\">Ostatnie 14 dni<\/option><option value=\"30daysAgo\" selected>Ostatnie 30 dni (zalecane)<\/option><option value=\"60daysAgo\">Ostatnie 60 dni<\/option><\/select>\n            <\/div>\n<div>\n                <label style=\"color: var(--text-secondary); display: block; font-size: 0.85rem; margin-bottom: 6px;\">Minimalna liczba sesji:<\/label><br \/>\n                <select id=\"ga4-min-sessions\" style=\"width: 100%; padding: 10px; background: var(--bg-panel); color: var(--text-primary); border: 1px solid var(--border); border-radius: 6px;\"><option value=\"5\">od 5 sesji<\/option><option value=\"10\" selected>od 10 sesji (domy\u015blnie)<\/option><option value=\"25\">od 25 sesji (tylko du\u017ce kohorty)<\/option><\/select>\n            <\/div>\n<\/p><\/div>\n<div style=\"display: flex; justify-content: flex-end;\">\n            <button id=\"run-bot-scan-btn\" class=\"button\" style=\"background: var(--accent); color: #0b1114; border: none; padding: 11px 26px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Skanuj ruch pod k\u0105tem kohort bot\u00f3w<\/button>\n        <\/div>\n<\/p><\/div>\n<p>    <!-- PASEK STATUSU I PODSUMOWANIA --><\/p>\n<div id=\"bot-summary-bar\" style=\"margin-bottom: 20px;\"><\/div>\n<p>    <!-- OBSZAR WYNIKOW --><\/p>\n<div id=\"bot-results-container\"><\/div>\n<\/div>\n<p><script>\n(() => {\n    let accessToken = null;\n    let tokenClient = null;<\/p>\n<p>    const authBtn = document.getElementById(\"ga4-auth-btn\");\n    const authStatus = document.getElementById(\"ga4-auth-status\");\n    const configPanel = document.getElementById(\"ga4-config-panel\");\n    const runScanBtn = document.getElementById(\"run-bot-scan-btn\");\n    const summaryBar = document.getElementById(\"bot-summary-bar\");\n    const resultsContainer = document.getElementById(\"bot-results-container\");<\/p>\n<p>    \/\/ Etykieta przycisku trzymana w jednym miejscu\n    const SCAN_LABEL = \"Skanuj ruch pod k\u0105tem kohort bot\u00f3w\";<\/p>\n<p>    \/\/ Bezpieczne zamiany unicode, aby WordPress nie rozbija\u0142 encji\n    const esc = (str) => String(str).replace(\/u0026\/g, \"&amp;\").replace(\/u003c\/g, \"&lt;\").replace(\/u003e\/g, \"&gt;\");<\/p>\n<p>    \/\/ 1. INICJALIZACJA OAUTH 2.0\n    authBtn.addEventListener(\"click\", () => {\n        const clientId = document.getElementById(\"ga4-client-id\").value.trim();\n        if (!clientId) {\n            alert(\"Prosz\u0119 poda\u0107 prawid\u0142owy identyfikator klienta Google Cloud.\");\n            return;\n        }<\/p>\n<p>        let gsiReady = false;\n        if (window.google) {\n            if (google.accounts) {\n                if (google.accounts.oauth2) {\n                    gsiReady = true;\n                }\n            }\n        }<\/p>\n<p>        if (!gsiReady) {\n            alert(\"Skrypt Google Identity Services wci\u0105\u017c si\u0119 wczytuje. Prosz\u0119 spr\u00f3bowa\u0107 za chwil\u0119.\");\n            return;\n        }<\/p>\n<p>        tokenClient = google.accounts.oauth2.initTokenClient({\n            client_id: clientId,\n            scope: \"https:\/\/www.googleapis.com\/auth\/analytics.readonly\",\n            callback: (resp) => {\n                if (resp.error) {\n                    authStatus.innerHTML = \"Status: <strong style='color:#ff6b6b;'>B\u0142\u0105d autoryzacji: \" + esc(resp.error) + \"<\/strong>\";\n                    return;\n                }\n                accessToken = resp.access_token;\n                authStatus.innerHTML = \"Status: <strong style='color:#51cf66;'>Po\u0142\u0105czono (Analytics, tylko odczyt)<\/strong>\";\n                configPanel.style.display = \"block\";\n            }\n        });\n        tokenClient.requestAccessToken();\n    });<\/p>\n<p>    \/\/ 2. MODU\u0141 HEURYSTYK (logika bezpieczna dla filtr\u00f3w WP)\n    const evaluateBotBehavior = (row) => {\n        const browser = row.dimensionValues[0].value;\n        const os = row.dimensionValues[1].value;\n        const country = row.dimensionValues[2].value;\n        const sourceMedium = row.dimensionValues[3].value;<\/p>\n<p>        const sessions = Number(row.metricValues[0].value ? row.metricValues[0].value : 0);\n        const pageviews = Number(row.metricValues[1].value ? row.metricValues[1].value : 0);\n        const engagementRate = parseFloat(row.metricValues[2].value ? row.metricValues[2].value : 0);\n        const bounceRate = parseFloat(row.metricValues[3].value ? row.metricValues[3].value : 0);\n        const avgSessionDuration = parseFloat(row.metricValues[4].value ? row.metricValues[4].value : 0);<\/p>\n<p>        const viewsPerSession = sessions > 0 ? pageviews \/ sessions : 0;<\/p>\n<p>        let botScore = 0;\n        const flags = [];<\/p>\n<p>        \/\/ Regu\u0142a 1: ruch bez \u017cadnego zaanga\u017cowania (0-2%)\n        if (engagementRate <= 0.02) {\n            botScore += 40;\n            flags.push(\"Brak zaanga\u017cowania (\" + (engagementRate * 100).toFixed(1) + \"% aktywnych sesji)\");\n        }\n\n        \/\/ Regu\u0142a 2: crawler jednostronicowy (dok\u0142adnie 1 ods\u0142ona na sesj\u0119 i co najmniej 95% odrzuce\u0144)\n        if (viewsPerSession <= 1.05) {\n            if (bounceRate >= 0.95) {\n                botScore += 35;\n                flags.push(\"Crawler jednostronicowy (\" + viewsPerSession.toFixed(2) + \" ods\u0142on\/sesj\u0119)\");\n            }\n        }<\/p>\n<p>        \/\/ Regu\u0142a 3: zerowy czas trwania sesji\n        if (avgSessionDuration <= 1.0) {\n            botScore += 25;\n            flags.push(\"Zerowy czas trwania sesji (\" + avgSessionDuration.toFixed(1) + \" s)\");\n        }\n\n        \/\/ Regu\u0142a 4: podejrzane kombinacje systemu i przegl\u0105darki\n        \/\/ Uwaga: por\u00f3wnywane warto\u015bci pochodz\u0105 z GA4 API i pozostaj\u0105 po angielsku.\n        const lowBrowser = browser.toLowerCase();\n        const lowOs = os.toLowerCase();\n        const suspiciousTerms = [\"bot\", \"crawler\", \"spider\", \"headless\"];\n        let isSuspicious = suspiciousTerms.some(term => lowBrowser.includes(term));\n        if (lowOs.includes(\"linux\")) {\n            isSuspicious = true;\n        }\n        if (isSuspicious) {\n            botScore += 20;\n            flags.push(\"Podejrzana sygnatura (\" + browser + \" \/ \" + os + \")\");\n        }<\/p>\n<p>        \/\/ Regu\u0142a 5: du\u017cy ruch bezpo\u015bredni z centr\u00f3w danych bez zaanga\u017cowania\n        \/\/ Uwaga: \"(direct)\" to warto\u015b\u0107 GA4 API i pozostaje bez zmian.\n        if (sourceMedium.toLowerCase().includes(\"(direct)\")) {\n            if (engagementRate === 0) {\n                botScore += 15;\n                flags.push(\"Ruch bezpo\u015bredni bez zaanga\u017cowania\");\n            }\n        }<\/p>\n<p>        return {\n            browser: browser,\n            os: os,\n            country: country,\n            sourceMedium: sourceMedium,\n            sessions: sessions,\n            pageviews: pageviews,\n            engagementRate: engagementRate,\n            bounceRate: bounceRate,\n            avgSessionDuration: avgSessionDuration,\n            viewsPerSession: viewsPerSession,\n            score: Math.min(botScore, 100),\n            flags: flags\n        };\n    };<\/p>\n<p>    const getSeverityBadge = (score) => {\n        if (score >= 80) {\n            return \"<span style='background:#471a1a; color:#ff6b6b; padding:4px 10px; border-radius:4px; font-size:0.75rem; font-weight:700; text-transform:uppercase;'>Bot krytyczny (\" + score + \"%)<\/span>\";\n        }\n        if (score >= 60) {\n            return \"<span style='background:#4b3a1a; color:#ff922b; padding:4px 10px; border-radius:4px; font-size:0.75rem; font-weight:700; text-transform:uppercase;'>Wysokie prawdopodobie\u0144stwo (\" + score + \"%)<\/span>\";\n        }\n        return \"<span style='background:#242b30; color:#a0a6b0; padding:4px 10px; border-radius:4px; font-size:0.75rem; font-weight:700; text-transform:uppercase;'>Umiarkowane (\" + score + \"%)<\/span>\";\n    };<\/p>\n<p>    \/\/ 3. POBRANIE RAPORTU Z GA4 DATA API\n    runScanBtn.addEventListener(\"click\", async () => {\n        const propertyId = document.getElementById(\"ga4-property-id\").value.trim().replace(\/^properties\/\/i, \"\");\n        const timeframe = document.getElementById(\"ga4-timeframe\").value;\n        const minSessions = parseInt(document.getElementById(\"ga4-min-sessions\").value, 10) || 10;<\/p>\n<p>        if (!propertyId || isNaN(propertyId)) {\n            alert(\"Prosz\u0119 poda\u0107 prawid\u0142owy numeryczny identyfikator us\u0142ugi GA4 (np. 345678901).\");\n            return;\n        }<\/p>\n<p>        runScanBtn.disabled = true;\n        runScanBtn.textContent = \"Skanowanie kohort ruchu GA4\u2026\";\n        summaryBar.innerHTML = \"\";\n        resultsContainer.innerHTML = \"\";<\/p>\n<p>        try {\n            const response = await fetch(\"https:\/\/analyticsdata.googleapis.com\/v1beta\/properties\/\" + propertyId + \":runReport\", {\n                method: \"POST\",\n                headers: {\n                    \"Authorization\": \"Bearer \" + accessToken,\n                    \"Content-Type\": \"application\/json\"\n                },\n                body: JSON.stringify({\n                    dateRanges: [{ startDate: timeframe, endDate: \"yesterday\" }],\n                    dimensions: [\n                        { name: \"browser\" },\n                        { name: \"operatingSystem\" },\n                        { name: \"country\" },\n                        { name: \"sessionSourceMedium\" }\n                    ],\n                    metrics: [\n                        { name: \"sessions\" },\n                        { name: \"screenPageViews\" },\n                        { name: \"engagementRate\" },\n                        { name: \"bounceRate\" },\n                        { name: \"averageSessionDuration\" }\n                    ],\n                    limit: 2500\n                })\n            });<\/p>\n<p>            if (!response.ok) {\n                const errJson = await response.json().catch(() => ({}));\n                const errMsg = errJson.error ? errJson.error.message : response.statusText;\n                throw new Error(errMsg);\n            }<\/p>\n<p>            const data = await response.json();\n            const rows = data.rows ? data.rows : [];\n            const totalCohortsScanned = rows.length;<\/p>\n<p>            let totalSessionsScanned = 0;\n            let totalBotSessions = 0;\n            const botCohorts = [];<\/p>\n<p>            rows.forEach(row => {\n                const result = evaluateBotBehavior(row);\n                totalSessionsScanned += result.sessions;<\/p>\n<p>                if (result.sessions >= minSessions) {\n                    if (result.score >= 60) {\n                        botCohorts.push(result);\n                        totalBotSessions += result.sessions;\n                    }\n                }\n            });<\/p>\n<p>            \/\/ Sortowanie malej\u0105co wed\u0142ug liczby sesji\n            botCohorts.sort((a, b) => b.sessions - a.sessions);<\/p>\n<p>            \/\/ 4. WY\u015aWIETLENIE PODSUMOWANIA I WYNIK\u00d3W\n            summaryBar.innerHTML = [\n                \"<\/p>\n<div style='background:var(--bg-body); padding:16px 20px; border-radius:8px; border:1px solid var(--border); display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:15px;'>\",\n                \"  <\/p>\n<div>\",\n                \"    <span style='color:var(--text-secondary); font-size:0.85rem; display:block;'>Przeskanowane kohorty ruchu<\/span>\",\n                \"    <strong style='color:var(--accent); font-size:1.4rem;'>\" + totalCohortsScanned.toLocaleString() + \" segment\u00f3w<\/strong>\",\n                \"  <\/div>\n<p>\",\n                \"  <\/p>\n<div>\",\n                \"    <span style='color:var(--text-secondary); font-size:0.85rem; display:block;'>Ocenione sesje<\/span>\",\n                \"    <strong style='color:var(--text-primary); font-size:1.4rem;'>\" + totalSessionsScanned.toLocaleString() + \" sesji<\/strong>\",\n                \"  <\/div>\n<p>\",\n                \"  <\/p>\n<div>\",\n                \"    <span style='color:var(--text-secondary); font-size:0.85rem; display:block;'>Oznaczony ruch bot\u00f3w<\/span>\",\n                \"    <strong style='color:\" + (botCohorts.length > 0 ? \"#ff6b6b\" : \"#51cf66\") + \"; font-size:1.4rem;'>\" + totalBotSessions.toLocaleString() + \" sesji (\" + botCohorts.length + \" kohort)<\/strong>\",\n                \"  <\/div>\n<p>\",\n                \"<\/p><\/div>\n<p>\"\n            ].join(\"\");<\/p>\n<p>            if (botCohorts.length === 0) {\n                resultsContainer.innerHTML = \"<\/p>\n<div style='background:var(--bg-body); padding:30px; border-radius:8px; border:1px solid var(--border); text-align:center; color:#51cf66; font-weight:bold; font-size:1.1rem;'>\u2714 Czysta us\u0142uga: w \" + totalCohortsScanned + \" segmentach ruchu nie wykryto kohort automatycznych crawler\u00f3w ani bot\u00f3w widmo.<\/div>\n<p>\";\n                return;\n            }<\/p>\n<p>            const cardsHtml = botCohorts.map(b => {\n                const flagsHtml = b.flags.map(f => [\n                    \"<span style='background:rgba(255,107,107,0.12); border:1px solid rgba(255,107,107,0.3); color:#ff6b6b; padding:4px 10px; border-radius:20px; font-size:0.8rem; font-weight:600;'>\" + esc(f) + \"<\/span>\"\n                ].join(\"\")).join(\" \");<\/p>\n<p>                return [\n                    \"<\/p>\n<div style='background:var(--bg-body); border:1px solid var(--border); border-radius:8px; padding:18px; margin-bottom:15px;'>\",\n                    \"  <\/p>\n<div style='display:flex; justify-content:space-between; align-items:flex-start; flex-wrap:wrap; gap:10px; border-bottom:1px solid var(--border); padding-bottom:12px; margin-bottom:12px;'>\",\n                    \"    <\/p>\n<div style='flex:1; min-width:260px;'>\",\n                    \"      <\/p>\n<div style='color:var(--text-secondary); font-size:0.8rem; text-transform:uppercase; font-weight:700; margin-bottom:4px;'>\" + esc(b.country) + \" &bull; \" + esc(b.sourceMedium) + \"<\/div>\n<p>\",\n                    \"      <strong style='color:var(--text-primary); font-size:1.15rem; display:block;'>\" + esc(b.browser) + \" w systemie \" + esc(b.os) + \"<\/strong>\",\n                    \"    <\/div>\n<p>\",\n                    \"    <\/p>\n<div style='text-align:right;'>\",\n                    \"      <\/p>\n<div style='color:var(--accent); font-weight:700; font-size:1.1rem; margin-bottom:4px;'>\" + b.sessions.toLocaleString() + \" sesji <span style='color:var(--text-secondary); font-size:0.85rem; font-weight:normal;'>(\" + b.pageviews.toLocaleString() + \" ods\u0142on)<\/span><\/div>\n<p>\",\n                    \"      \" + getSeverityBadge(b.score),\n                    \"    <\/p><\/div>\n<p>\",\n                    \"  <\/p><\/div>\n<p>\",\n                    \"  <\/p>\n<div style='display:flex; gap:20px; flex-wrap:wrap; margin-bottom:12px; font-family:monospace; font-size:0.85rem; color:var(--text-secondary);'>\",\n                    \"    <\/p>\n<div>Zaanga\u017cowanie: <strong style='color:\" + (b.engagementRate === 0 ? \"#ff6b6b\" : \"var(--text-primary)\") + \";'>\" + (b.engagementRate * 100).toFixed(1) + \"%<\/strong><\/div>\n<p>\",\n                    \"    <\/p>\n<div>Wsp\u00f3\u0142czynnik odrzuce\u0144: <strong style='color:var(--text-primary);'>\" + (b.bounceRate * 100).toFixed(1) + \"%<\/strong><\/div>\n<p>\",\n                    \"    <\/p>\n<div>\u015ar. czas: <strong style='color:var(--text-primary);'>\" + b.avgSessionDuration.toFixed(1) + \" s<\/strong><\/div>\n<p>\",\n                    \"    <\/p>\n<div>Ods\u0142ony\/sesj\u0119: <strong style='color:var(--text-primary);'>\" + b.viewsPerSession.toFixed(2) + \"<\/strong><\/div>\n<p>\",\n                    \"  <\/p><\/div>\n<p>\",\n                    \"  <\/p>\n<div style='display:flex; gap:8px; flex-wrap:wrap; align-items:center;'>\",\n                    \"    <span style='color:var(--text-secondary); font-size:0.8rem; font-weight:600;'>Wykryte wska\u017aniki:<\/span>\",\n                    \"    \" + flagsHtml,\n                    \"  <\/div>\n<p>\",\n                    \"<\/p><\/div>\n<p>\"\n                ].join(\"\");\n            }).join(\"\");<\/p>\n<p>            resultsContainer.innerHTML = [\n                \"<\/p>\n<h3 style='color:var(--text-primary); margin-bottom:15px; font-size:1.15rem;'>Wykryte kohorty bot\u00f3w i crawler\u00f3w (\" + botCohorts.length + \")<\/h3>\n<p>\",\n                cardsHtml\n            ].join(\"\");<\/p>\n<p>        } catch (e) {\n            resultsContainer.innerHTML = \"<\/p>\n<div style='background:var(--bg-body); padding:25px; border-radius:8px; border:1px solid #ff6b6b; color:#ff6b6b; font-weight:bold;'>B\u0142\u0105d GA4 API: \" + esc(e.message) + \"<\/div>\n<p>\";\n        } finally {\n            runScanBtn.disabled = false;\n            runScanBtn.textContent = SCAN_LABEL;\n        }\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0141\u0105czy si\u0119 z GA4 Data API przez OAuth i przeszukuje segmenty ruchu pod k\u0105tem kohort bot\u00f3w i crawler\u00f3w.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"class_list":["post-9304","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog<\/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\/pl\/narzedzia\/ga4-bot-detector\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"\u0141\u0105czy si\u0119 z GA4 Data API przez OAuth i przeszukuje segmenty ruchu pod k\u0105tem kohort bot\u00f3w i crawler\u00f3w.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\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\\\/pl\\\/narzedzia\\\/ga4-bot-detector\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/ga4-bot-detector\\\/\",\"name\":\"Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-08-09T13:37:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/ga4-bot-detector\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/ga4-bot-detector\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/ga4-bot-detector\\\/#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\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Detektor bot\u00f3w GA4\"}]},{\"@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\":\"luky\",\"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\":\"luky\"},\"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":"Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog","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\/pl\/narzedzia\/ga4-bot-detector\/","og_locale":"en_US","og_type":"article","og_title":"Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog","og_description":"\u0141\u0105czy si\u0119 z GA4 Data API przez OAuth i przeszukuje segmenty ruchu pod k\u0105tem kohort bot\u00f3w i crawler\u00f3w.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/","og_site_name":"Lukas Wojcik - Blog","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\/pl\/narzedzia\/ga4-bot-detector\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/","name":"Detektor bot\u00f3w GA4 - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-08-09T13:37:09+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/ga4-bot-detector\/#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\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Detektor bot\u00f3w GA4"}]},{"@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":"luky","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":"luky"},"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\/9304","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=9304"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9304\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=9304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}