{"id":13108,"date":"2026-09-20T07:35:00","date_gmt":"2026-09-20T05:35:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=13108"},"modified":"2026-10-26T13:29:23","modified_gmt":"2026-10-26T12:29:23","slug":"tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/","title":{"rendered":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It"},"content":{"rendered":"<p>An email address in a URL path, a search term containing a phone number or a personal order reference can reach GA4 together with an event. The finding creates two separate tasks: prevent further transmission and address stored data. Changing a tag does not clean historical reports.<\/p>\n<p>The workflow below starts with an inventory, then limits collection and finally considers deletion. No single report or regular expression can prove the absence of personal data.<\/p>\n<figure class=\"lw-diagram\"><img src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/dia-13108-review-20261024.png\" width=\"1120\" height=\"580\" decoding=\"async\" loading=\"lazy\" alt=\"Personal data in GA4: three separate tasks\"><figcaption>The tasks are finding sources, preventing further transmission and treating stored data separately. Every stage has limits.<\/figcaption><\/figure>\n<h2>1. Affected values and transmission routes<\/h2>\n<p>Email addresses and personal phone numbers are obvious examples. An order number or password-reset token can also identify a person when combined with available additional information. A token is also a secret. Calling a value pseudonymous or hashing the value does not automatically remove the connection to a person. PII stands for personally identifiable information. Google&#8217;s PII rules and the legal concept of personal data are not identical.<\/p>\n<p>The investigation covers full page addresses, paths, query parameters, referrers, page titles, search terms and custom event parameters. The GA4 default for <code>page_location<\/code> excludes the URL fragment after <code>#<\/code>. JavaScript or a different implementation can still explicitly transmit fragments. A fragment is therefore not a secure storage location for secrets.<\/p>\n<p>A finding record needs the source, parameter, period, affected destinations and a sanitized example. Full tokens or addresses do not belong in tickets, broadly accessible spreadsheets or public online checkers. Exposed access or reset tokens also require invalidation; later removal from reports is insufficient.<\/p>\n<h2>2. Queries of available reports<\/h2>\n<p>The Data API provides report data, not a complete raw-data inventory. <code>pageLocation<\/code> includes the page address with host and query; <code>pagePathPlusQueryString<\/code> includes path and query. <code>pagePath<\/code> alone omits query parameters. Separate queries using <code>pageReferrer<\/code> and <code>searchTerm<\/code> cover other possible locations. Sending a custom parameter does not automatically create a queryable custom dimension.<\/p>\n<p>This example is the JSON body for an authenticated POST request to <code>https:\/\/analyticsdata.googleapis.com\/v1beta\/properties\/PROPERTY_ID:runReport<\/code>. The request requires the numeric property ID, read access and an appropriate OAuth scope such as <code>analytics.readonly<\/code>. The fixed date range is illustrative and must match the investigated incident.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"json\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">JSON<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-json\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\">{\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"dateRanges\"<\/span>: &#91;\n<\/span><span class=\"cbb-line\">    {\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">\"startDate\"<\/span>: <span class=\"cbb-string\">\"2026-10-01\"<\/span>,\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">\"endDate\"<\/span>: <span class=\"cbb-string\">\"2026-10-07\"<\/span>\n<\/span><span class=\"cbb-line\">    }\n<\/span><span class=\"cbb-line\">  &#93;,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"dimensions\"<\/span>: &#91;\n<\/span><span class=\"cbb-line\">    {\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">\"name\"<\/span>: <span class=\"cbb-string\">\"pageLocation\"<\/span>\n<\/span><span class=\"cbb-line\">    }\n<\/span><span class=\"cbb-line\">  &#93;,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"metrics\"<\/span>: &#91;\n<\/span><span class=\"cbb-line\">    {\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">\"name\"<\/span>: <span class=\"cbb-string\">\"eventCount\"<\/span>\n<\/span><span class=\"cbb-line\">    }\n<\/span><span class=\"cbb-line\">  &#93;,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"orderBys\"<\/span>: &#91;\n<\/span><span class=\"cbb-line\">    {\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">\"dimension\"<\/span>: {\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">\"dimensionName\"<\/span>: <span class=\"cbb-string\">\"pageLocation\"<\/span>,\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-attr\">\"orderType\"<\/span>: <span class=\"cbb-string\">\"ALPHANUMERIC\"<\/span>\n<\/span><span class=\"cbb-line\">      }\n<\/span><span class=\"cbb-line\">    }\n<\/span><span class=\"cbb-line\">  &#93;,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"limit\"<\/span>: <span class=\"cbb-string\">\"10000\"<\/span>,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"offset\"<\/span>: <span class=\"cbb-string\">\"0\"<\/span>,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">\"returnPropertyQuota\"<\/span>: <span class=\"cbb-constant\">true<\/span>\n<\/span><span class=\"cbb-line\">}<\/span><\/code><\/pre><\/figure>\n<p><code>eventCount<\/code> counts events; page views would be unsuitable for a separate search-term query. Pagination sets <code>offset<\/code> to the number of rows already retrieved until the reported <code>rowCount<\/code> is reached. Alphabetical sorting and a fixed range make pagination easier, but late-arriving data can still change the results. The API permits at most 250,000 rows per request, and quotas still apply.<\/p>\n<p>Response checks include <code>dataLossFromOtherRow<\/code>, <code>samplingMetadatas<\/code>, <code>dataTruncationReasons<\/code> and <code>subjectToThresholding<\/code>. The last flag indicates that thresholds apply, not necessarily that rows were withheld. Fetching further pages does not restore values grouped into \u201c(other)\u201d, truncated data or unavailable history. Even clear metadata does not establish a complete privacy audit.<\/p>\n<h2>3. Detection of leads and assessment of context<\/h2>\n<p>Percent encoding represents characters in a URL with codes; for example, %40 represents @. Decoding turns those codes back into characters. The Python example checks the original text and up to two additional rounds of percent decoding. Query parsing handles repeated and empty parameters and encoded key names. Inspecting a fragment only describes the input text; the result does not establish actual collection by GA4.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"python\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Python<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-python\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-keyword\">import<\/span> re\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">from<\/span> urllib.parse <span class=\"cbb-keyword\">import<\/span> parse_qsl, unquote, urlsplit\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">EMAIL = re.<span class=\"cbb-function\">compile<\/span>(<span class=\"cbb-string\">r\"&#91;A-Z0-9.!#$%&amp;'*+\/=?^_`{|}~-&#93;+@&#91;A-Z0-9-&#93;+(?:\\.&#91;A-Z0-9-&#93;+)+\"<\/span>, re.I)\n<\/span><span class=\"cbb-line\">FIELDS = {\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-string\">\"secret_field\"<\/span>: {<span class=\"cbb-string\">\"token\"<\/span>, <span class=\"cbb-string\">\"hash\"<\/span>, <span class=\"cbb-string\">\"auth\"<\/span>, <span class=\"cbb-string\">\"key\"<\/span>, <span class=\"cbb-string\">\"sig\"<\/span>, <span class=\"cbb-string\">\"pwd\"<\/span>, <span class=\"cbb-string\">\"password\"<\/span>},\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-string\">\"name_field\"<\/span>: {<span class=\"cbb-string\">\"name\"<\/span>, <span class=\"cbb-string\">\"vorname\"<\/span>, <span class=\"cbb-string\">\"nachname\"<\/span>, <span class=\"cbb-string\">\"firstname\"<\/span>, <span class=\"cbb-string\">\"lastname\"<\/span>, <span class=\"cbb-string\">\"user\"<\/span>},\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-string\">\"phone_field\"<\/span>: {<span class=\"cbb-string\">\"phone\"<\/span>, <span class=\"cbb-string\">\"tel\"<\/span>, <span class=\"cbb-string\">\"mobile\"<\/span>, <span class=\"cbb-string\">\"telephone\"<\/span>},\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-string\">\"search_field\"<\/span>: {<span class=\"cbb-string\">\"q\"<\/span>, <span class=\"cbb-string\">\"s\"<\/span>, <span class=\"cbb-string\">\"search\"<\/span>, <span class=\"cbb-string\">\"query\"<\/span>},\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">scan_url<\/span>(text):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(text, str):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">raise<\/span> <span class=\"cbb-function\">TypeError<\/span>(<span class=\"cbb-string\">\"text must be a string\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">len<\/span>(text) &gt; <span class=\"cbb-number\">16384<\/span>:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> {<span class=\"cbb-string\">\"input_too_long\"<\/span>}\n<\/span><span class=\"cbb-line\">    flags = <span class=\"cbb-function\">set<\/span>()\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> re.<span class=\"cbb-function\">search<\/span>(<span class=\"cbb-string\">r\"%(?!&#91;0-9a-fA-F&#93;{2})\"<\/span>, text):\n<\/span><span class=\"cbb-line\">        flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"invalid_percent_encoding\"<\/span>)\n<\/span><span class=\"cbb-line\">    forms = &#91;text&#93;\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">for<\/span> _ <span class=\"cbb-keyword\">in<\/span> <span class=\"cbb-function\">range<\/span>(<span class=\"cbb-number\">2<\/span>):\n<\/span><span class=\"cbb-line\">        decoded = <span class=\"cbb-function\">unquote<\/span>(forms&#91;<span class=\"cbb-number\">-1<\/span>&#93;)\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">if<\/span> decoded == forms&#91;<span class=\"cbb-number\">-1<\/span>&#93;:\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-keyword\">break<\/span>\n<\/span><span class=\"cbb-line\">        forms.<span class=\"cbb-function\">append<\/span>(decoded)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">unquote<\/span>(forms&#91;<span class=\"cbb-number\">-1<\/span>&#93;) != forms&#91;<span class=\"cbb-number\">-1<\/span>&#93;:\n<\/span><span class=\"cbb-line\">        flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"further_encoding\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">for<\/span> form <span class=\"cbb-keyword\">in<\/span> forms:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">if<\/span> EMAIL.<span class=\"cbb-function\">search<\/span>(form):\n<\/span><span class=\"cbb-line\">            flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"email_like\"<\/span>)\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">try<\/span>:\n<\/span><span class=\"cbb-line\">            parts = <span class=\"cbb-function\">urlsplit<\/span>(form)\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-keyword\">if<\/span> parts.username <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-constant\">None<\/span> <span class=\"cbb-keyword\">or<\/span> parts.password <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-constant\">None<\/span>:\n<\/span><span class=\"cbb-line\">                flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"url_credentials\"<\/span>)\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-comment\"># Fragment query syntax is inspected too, without claiming collection.<\/span>\n<\/span><span class=\"cbb-line\">            queries = &#91;parts.query, parts.fragment.<span class=\"cbb-function\">partition<\/span>(<span class=\"cbb-string\">\"?\"<\/span>)&#91;<span class=\"cbb-number\">2<\/span>&#93; <span class=\"cbb-keyword\">or<\/span> parts.fragment&#93;\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-keyword\">for<\/span> query <span class=\"cbb-keyword\">in<\/span> queries:\n<\/span><span class=\"cbb-line\">                <span class=\"cbb-keyword\">for<\/span> key, value <span class=\"cbb-keyword\">in<\/span> <span class=\"cbb-function\">parse_qsl<\/span>(query, keep_blank_values=<span class=\"cbb-constant\">True<\/span>, max_num_fields=<span class=\"cbb-number\">1000<\/span>):\n<\/span><span class=\"cbb-line\">                    <span class=\"cbb-keyword\">for<\/span> label, names <span class=\"cbb-keyword\">in<\/span> FIELDS.<span class=\"cbb-function\">items<\/span>():\n<\/span><span class=\"cbb-line\">                        <span class=\"cbb-keyword\">if<\/span> key.<span class=\"cbb-function\">casefold<\/span>() <span class=\"cbb-keyword\">in<\/span> names:\n<\/span><span class=\"cbb-line\">                            flags.<span class=\"cbb-function\">add<\/span>(label)\n<\/span><span class=\"cbb-line\">                    <span class=\"cbb-keyword\">if<\/span> EMAIL.<span class=\"cbb-function\">search<\/span>(value):\n<\/span><span class=\"cbb-line\">                        flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"email_like\"<\/span>)\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">except<\/span> ValueError:\n<\/span><span class=\"cbb-line\">            flags.<span class=\"cbb-function\">add<\/span>(<span class=\"cbb-string\">\"url_parse_error\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> flags<\/span><\/code><\/pre><\/figure>\n<p>The function returns categories rather than raw values. <code>email_like<\/code> marks an email-like pattern, while <code>secret_field<\/code> marks a suspicious key name. <code>phone_field<\/code> establishes neither a valid phone number nor a connection to a person. A product search term or <code>name=product<\/code> can also trigger a review flag. The number <code>20260920<\/code> is not automatically classified as a phone number.<\/p>\n<p>Blind spots include unknown parameter names, personal numeric identifiers in paths, Unicode edge cases, deeper encoding and encrypted content. Decoded separators can introduce additional false positives. <code>input_too_long<\/code>, <code>url_parse_error<\/code> and <code>further_encoding<\/code> require separate investigation. An empty result only means that these limited rules found nothing. Samples support contextual assessment but cannot replace examination of all relevant sources.<\/p>\n<h2>4. Prevention of further transmission at the source<\/h2>\n<p>A URL without sensitive values protects more than a downstream correction of an analytics field. Where personal form input is necessary, POST avoids the usual placement of form fields in the query string. POST does not prevent form-data tracking, request-body logs, problematic redirects or a later URL containing the same values.<\/p>\n<p>A suitable implementation collects permitted fields with a defined purpose and sanitizes page addresses, referrers, titles and free text before transmission. Server-side tagging can add checks before forwarding. Browser requests already sent to other destinations and direct routes bypassing the server container remain unaffected.<\/p>\n<p>GA4 web-stream data redaction provides an additional layer. Email detection is best effort; values of configured query keys are replaced with a redaction marker in the documented URL parameters, including <code>page_location<\/code> and <code>page_referrer<\/code>. Processing takes place on the client. Measurement Protocol, Data Import and HTTP headers are outside this feature&#8217;s coverage. The setting does not clean historical values.<\/p>\n<p>Controlled tests use invented values such as <code>test@example.invalid<\/code>. The decisive evidence is the outgoing request after all tag rules: initial load, navigation, internal search, form completion and every transmission route. A correct preview display alone does not prove correct production transmission.<\/p>\n<h2>5. Historical GA4 data: deletion types and exceptions<\/h2>\n<p>Administration provides data-deletion requests for supported parameters and periods. Dates follow the property&#8217;s time zone. For automatically collected parameters, the documentation requires the broad \u201cDelete all parameters on all events\u201d type; apparently selecting <code>page_location<\/code> alone is not a general substitute. Registering an additional custom dimension does not bypass that restriction.<\/p>\n<p><strong>A significant limit:<\/strong> Google explicitly lists <code>search_term<\/code> among parameters that this mechanism cannot delete. Other documented exceptions also apply. An incident involving search terms cannot be considered resolved merely because a request for other parameters has finished. The specific case requires an appropriate additional resolution, potentially involving Google support.<\/p>\n<p>The mechanism affects text values, not numeric parameter values, and retains event counts. Supported values receive a deletion marker; the broad deletion type can also affect event names. User-ID-related deletion has a separate route. Parameter deletion is therefore neither removal of entire events nor deletion of all personal data involved in a case.<\/p>\n<p>A request can be cancelled for seven days. Processing can take seven to 63 days overall, and data must be more than twelve days old. An optional contains filter compares text without case sensitivity. Preview and temporary exclusion do not establish completed deletion. Scope, status and reporting effects need documentation.<\/p>\n<h2>6. BigQuery and other copies require separate treatment<\/h2>\n<p>A GA4 deletion request does not replace cleaning previously exported data. The following inventory counts parameter occurrences and value types in one exact table without exposing the values. Project, dataset, date and keys must match the actual findings.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"sql\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">SQL<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-sql\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">-- Review one closed daily table; no modification is performed.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">DECLARE<\/span> target_keys <span class=\"cbb-keyword\">ARRAY<\/span>&lt;<span class=\"cbb-type\">STRING<\/span>&gt; <span class=\"cbb-keyword\">DEFAULT<\/span>\n<\/span><span class=\"cbb-line\">  &#91;<span class=\"cbb-string\">'page_location'<\/span>, <span class=\"cbb-string\">'page_referrer'<\/span>, <span class=\"cbb-string\">'search_term'<\/span>&#93;;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">SELECT<\/span>\n<\/span><span class=\"cbb-line\">  p.<span class=\"cbb-keyword\">key<\/span>,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-function\">COUNT<\/span>(*) <span class=\"cbb-keyword\">AS<\/span> parameter_occurrences,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-function\">COUNTIF<\/span>(p.value.string_value <span class=\"cbb-keyword\">IS<\/span> <span class=\"cbb-keyword\">NOT<\/span> <span class=\"cbb-constant\">NULL<\/span>) <span class=\"cbb-keyword\">AS<\/span> text_values,\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-function\">COUNTIF<\/span>(p.value.int_value <span class=\"cbb-keyword\">IS<\/span> <span class=\"cbb-keyword\">NOT<\/span> <span class=\"cbb-constant\">NULL<\/span>\n<\/span><span class=\"cbb-line\">       <span class=\"cbb-keyword\">OR<\/span> p.value.float_value <span class=\"cbb-keyword\">IS<\/span> <span class=\"cbb-keyword\">NOT<\/span> <span class=\"cbb-constant\">NULL<\/span>\n<\/span><span class=\"cbb-line\">       <span class=\"cbb-keyword\">OR<\/span> p.value.double_value <span class=\"cbb-keyword\">IS<\/span> <span class=\"cbb-keyword\">NOT<\/span> <span class=\"cbb-constant\">NULL<\/span>) <span class=\"cbb-keyword\">AS<\/span> numeric_values\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">FROM<\/span> <span class=\"cbb-variable\">`project_id.analytics_123456789.events_20261001`<\/span>,\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">UNNEST<\/span>(event_params) <span class=\"cbb-keyword\">AS<\/span> p\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">WHERE<\/span> p.<span class=\"cbb-keyword\">key<\/span> <span class=\"cbb-keyword\">IN<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(target_keys)\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">GROUP<\/span> <span class=\"cbb-keyword\">BY<\/span> p.<span class=\"cbb-keyword\">key<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">ORDER<\/span> <span class=\"cbb-keyword\">BY<\/span> p.<span class=\"cbb-keyword\">key<\/span>;<\/span><\/code><\/pre><\/figure>\n<p>If full removal of these three parameters has been justified, the next example shows a limited implementation. With <code>apply_change = FALSE<\/code>, only a count of affected events runs. Switching to <code>TRUE<\/code> removes every entry with a selected key from this table, including harmless values. This destructively changes the current table; the operation is not precise masking of individual email addresses.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"sql\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">SQL<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-sql\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">-- Example for a confirmed full removal of selected parameter values.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">-- Project, dataset, table and key list require case-specific review.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">DECLARE<\/span> apply_change <span class=\"cbb-type\">BOOL<\/span> <span class=\"cbb-keyword\">DEFAULT<\/span> <span class=\"cbb-constant\">FALSE<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">DECLARE<\/span> target_keys <span class=\"cbb-keyword\">ARRAY<\/span>&lt;<span class=\"cbb-type\">STRING<\/span>&gt; <span class=\"cbb-keyword\">DEFAULT<\/span>\n<\/span><span class=\"cbb-line\">  &#91;<span class=\"cbb-string\">'page_location'<\/span>, <span class=\"cbb-string\">'page_referrer'<\/span>, <span class=\"cbb-string\">'search_term'<\/span>&#93;;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">SELECT<\/span> <span class=\"cbb-function\">COUNT<\/span>(*) <span class=\"cbb-keyword\">AS<\/span> affected_events\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">FROM<\/span> <span class=\"cbb-variable\">`project_id.analytics_123456789.events_20261001`<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">WHERE<\/span> <span class=\"cbb-keyword\">EXISTS<\/span> (\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-keyword\">SELECT<\/span> <span class=\"cbb-number\">1<\/span> <span class=\"cbb-keyword\">FROM<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(event_params) <span class=\"cbb-keyword\">AS<\/span> p\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-keyword\">WHERE<\/span> p.<span class=\"cbb-keyword\">key<\/span> <span class=\"cbb-keyword\">IN<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(target_keys)\n<\/span><span class=\"cbb-line\">);\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">IF<\/span> apply_change <span class=\"cbb-keyword\">THEN<\/span>\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-keyword\">UPDATE<\/span> <span class=\"cbb-variable\">`project_id.analytics_123456789.events_20261001`<\/span>\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-keyword\">SET<\/span> event_params = <span class=\"cbb-keyword\">ARRAY<\/span>(\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">SELECT<\/span> <span class=\"cbb-keyword\">AS<\/span> <span class=\"cbb-keyword\">STRUCT<\/span> p.*\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">FROM<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(event_params) <span class=\"cbb-keyword\">AS<\/span> p <span class=\"cbb-keyword\">WITH<\/span> <span class=\"cbb-keyword\">OFFSET<\/span> <span class=\"cbb-keyword\">AS<\/span> position\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">WHERE<\/span> p.<span class=\"cbb-keyword\">key<\/span> <span class=\"cbb-keyword\">IS<\/span> <span class=\"cbb-constant\">NULL<\/span> <span class=\"cbb-keyword\">OR<\/span> p.<span class=\"cbb-keyword\">key<\/span> <span class=\"cbb-keyword\">NOT<\/span> <span class=\"cbb-keyword\">IN<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(target_keys)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">ORDER<\/span> <span class=\"cbb-keyword\">BY<\/span> position\n<\/span><span class=\"cbb-line\">  )\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-keyword\">WHERE<\/span> <span class=\"cbb-keyword\">EXISTS<\/span> (\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">SELECT<\/span> <span class=\"cbb-number\">1<\/span> <span class=\"cbb-keyword\">FROM<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(event_params) <span class=\"cbb-keyword\">AS<\/span> p\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">WHERE<\/span> p.<span class=\"cbb-keyword\">key<\/span> <span class=\"cbb-keyword\">IN<\/span> <span class=\"cbb-keyword\">UNNEST<\/span>(target_keys)\n<\/span><span class=\"cbb-line\">  );\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">END<\/span> <span class=\"cbb-keyword\">IF<\/span>;<\/span><\/code><\/pre><\/figure>\n<p>Other parameter entries, including possible NULL keys, retain values and order. The target-key list must not contain NULL. Other tables, <code>user_properties<\/code>, user identifiers, additional event fields and downstream exports remain unchanged. Before a change, an isolated test table must establish the target, permissions, expected count and effects; an inventory query then checks the result. Active or late exports can add data again and require a separate check.<\/p>\n<p>BigQuery retains earlier versions through Time Travel, seven days by default and configurable from two to seven days. A seven-day fail-safe period follows. Those data are not directly queryable; recovery requires the documented support process. Snapshots, copies, downloads and other systems have separate lifecycles. An empty current query therefore does not establish immediate physical deletion of every copy.<\/p>\n<h2>7. Comparison of Collect requests without replaying them<\/h2>\n<p>The <a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/ga4-parameter-analyser\/\">GA4 Parameter Analyser<\/a> separates full Collect URLs or query-encoded request lines into parameters. Shared parameters from a POST URL can be entered in the separate input field. Multiple lines support comparison of event names, measurement IDs, repeated keys and missing versus empty values.<\/p>\n<p>The analysis function percent-decodes once, replaces plus signs according to form encoding and renders results as text. The function does not replay pasted requests. Measurement Protocol JSON is a different format; packed product values receive only heuristic parsing. CSV export is not anonymization. Sanitized or synthetic examples remain appropriate for investigation; a parameter view establishes neither GA4 receipt nor a complete PII check.<\/p>\n<h2>Frequently asked questions<\/h2>\n<h3>Is removing one query parameter sufficient?<\/h3>\n<p>Only for that exact location. Paths, referrers, titles, search, other parameters and additional transmission routes can contain the same value. The change also only affects future transmission.<\/p>\n<h3>Does Referrer-Policy prevent every disclosure?<\/h3>\n<p>Under <code>strict-origin-when-cross-origin<\/code>, same-origin requests can still carry the URL as referrer. Cross-origin requests normally carry only the origin, and an HTTPS-to-HTTP downgrade carries no referrer. Origin means scheme, host and port, rather than merely the same website. Different policies and explicitly assigned analytics parameters need separate checks.<\/p>\n<h3>Is a masked address automatically anonymous?<\/h3>\n<p>Masking can reduce information. Remaining identifiers, additional information and processing context still determine possible identification. Replacing a query value does not establish anonymity in general.<\/p>\n<h3>When has the technical incident been addressed?<\/h3>\n<p>When affected sources have been identified, future transmission has been checked, available deletion routes have completed and remaining copies or technical limits have been documented. A regex returning no matches or one cleaned report cannot establish those conditions alone.<\/p>\n<h2>Sources and technical references<\/h2><ul><li><a href=\"https:\/\/support.google.com\/analytics\/answer\/13544947?hl=en\">GA4: Data redaction<\/a><\/li><li><a href=\"https:\/\/support.google.com\/analytics\/answer\/9940393?hl=en\">GA4: Data-deletion requests<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/rest\/v1beta\/properties\/runReport\">Data API: runReport<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/rest\/v1beta\/ResponseMetaData\">Data API: ResponseMetaData<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\">Data API: Dimensions &amp; metrics<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/ga4\/views?hl=en\">GA4: Page views<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/bigquery\/docs\/time-travel\">BigQuery: Time Travel<\/a><\/li><li><a href=\"https:\/\/eur-lex.europa.eu\/eli\/reg\/2016\/679\/oj\/eng\/\">GDPR: Article 4<\/a><\/li><li><a href=\"https:\/\/eur-lex.europa.eu\/legal-content\/EN\/TXT\/?uri=CELEX%3A62022CJ0604\">CJEU: C-604\/22<\/a><\/li><li><a href=\"https:\/\/support.google.com\/analytics\/answer\/6366371?hl=en\">Google Analytics: PII<\/a><\/li><li><a href=\"https:\/\/docs.python.org\/3\/library\/urllib.parse.html\">Python: urllib.parse<\/a><\/li><li><a href=\"https:\/\/docs.cloud.google.com\/bigquery\/docs\/reference\/standard-sql\/dml-syntax\">BigQuery: DML<\/a><\/li><li><a href=\"https:\/\/developer.chrome.com\/blog\/referrer-policy-new-chrome-default\/\">Chrome: Referrer-Policy<\/a><\/li><li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/themes\/lw-theme\/js\/collect-analyser.js?v=20260928a\">GA4 Parameter Analyser: JavaScript<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/ga4\">GA4: Collection<\/a><\/li><li><a href=\"https:\/\/support.google.com\/analytics\/answer\/7201382?hl=en\">GA4: DebugView<\/a><\/li><li><a href=\"https:\/\/url.spec.whatwg.org\/#application\/x-www-form-urlencoded\">WHATWG: Form URL encoding<\/a><\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A practical workflow for finding personal data in GA4 URLs, preventing further transmission and assessing deletion options. Covers Data API limits, web redaction, GA4 deletion exceptions and separate BigQuery cleanup.<\/p>\n","protected":false},"author":1,"featured_media":28497,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[120],"tags":[91279,91270,91258,91114,91219],"class_list":["post-13108","post","type-post","status-publish","format-standard","hentry","category-tutorials-en","tag-prywatnosc-danych-pl","tag-gdpr","tag-google-analytics-4","tag-pii-protection","tag-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.\" \/>\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\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-20T05:35:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-26T12:29:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-13108-review-20261024-dark.png\" \/>\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\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It\",\"datePublished\":\"2026-09-20T05:35:00+00:00\",\"dateModified\":\"2026-10-26T12:29:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/\"},\"wordCount\":1592,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/lw-flux3-20261031\\\/hero-13108.png\",\"keywords\":[\"Data Privacy\",\"GDPR\",\"Google Analytics 4\",\"PII Protection\",\"Tutorial\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/\",\"name\":\"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/lw-flux3-20261031\\\/hero-13108.png\",\"datePublished\":\"2026-09-20T05:35:00+00:00\",\"dateModified\":\"2026-10-26T12:29:23+00:00\",\"description\":\"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/lw-flux3-20261031\\\/hero-13108.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/lw-flux3-20261031\\\/hero-13108.png\",\"width\":1200,\"height\":630,\"caption\":\"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/data-privacy\\\/tutorials-en\\\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It\"}]},{\"@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":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik","description":"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.","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\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/","og_locale":"en_US","og_type":"article","og_title":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik","og_description":"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-09-20T05:35:00+00:00","article_modified_time":"2026-10-26T12:29:23+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/hero-13108-review-20261024-dark.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It","datePublished":"2026-09-20T05:35:00+00:00","dateModified":"2026-10-26T12:29:23+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/"},"wordCount":1592,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/lw-flux3-20261031\/hero-13108.png","keywords":["Data Privacy","GDPR","Google Analytics 4","PII Protection","Tutorial"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/","name":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/lw-flux3-20261031\/hero-13108.png","datePublished":"2026-09-20T05:35:00+00:00","dateModified":"2026-10-26T12:29:23+00:00","description":"Listing every page path through the Data API, scanning it for personal data, redacting at the stream, and requesting deletion of what is already stored.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/lw-flux3-20261031\/hero-13108.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/lw-flux3-20261031\/hero-13108.png","width":1200,"height":630,"caption":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/data-privacy\/tutorials-en\/tutorial-finding-personal-data-in-ga4-page-paths-and-removing-it\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Tutorial: Finding Personal Data in GA4 Page Paths and Removing It"}]},{"@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\/posts\/13108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"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=13108"}],"version-history":[{"count":6,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/13108\/revisions"}],"predecessor-version":[{"id":27402,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/13108\/revisions\/27402"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/28497"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=13108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=13108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=13108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}