Do you want to come to Andalu-SEO?
Andalu-SEO

Use Cookies to Your Advantage in SEO

Descubre cómo usar las cookies en el mundo del Marketing

Use Cookies to Your Advantage in SEO
Author:
Carlos Sánchez
Topics:
Crawling
,
Technologies
Publication Date:
2025-12-04

Last Review:
2025-12-05

Cookies are a web element that has been heavily legislated without much understanding. But above all, it is an element that has been almost relegated to language changes, external analytics tools, and shopping carts.

However, we can use cookies for many purposes to our advantage. I encourage you to watch this video and let’s look at several practical cases.

It is important to emphasize the following: after reviewing it in detail, even if we are dealing with first-party analytical cookies or cookies intended to improve personalization, legally they must only be implemented after consent (remember that you can implement the consent mode yourself), unless they are strictly necessary for the page to function.

In any case, I recommend reviewing each situation with the legal department, as each specific case can be interpreted differently depending on the circumstances. Another idea is to store them in sessionStorage or localStorage until the user accepts, and then transfer them to persistent cookies.

I’m going to focus on examples of technical implementations that you could adapt and apply to your business.

As I said, these are examples that can serve to inspire you or give you ideas about the many possible applications.

ChatGPT UTM

To check whether our SEO strategy for LLMs is working, we can do a very simple test.

As of today, ChatGPT adds links with a UTM parameter, and if users visit our website, thanks to that parameter, we can track it in Google Analytics.

But what happens if we don’t have GA or want to check leads more directly?

We can make the website set a cookie for each page visited (or, if preferred, add all the steps into a single cookie in JSON format to avoid overloading the browser). I prefer to show it in a simple form so that each person can then optimize it as they like.

Tracking starts when the user accesses a URL with the defined UTM. From there, a cookie is created for each page in sequential order, so that in the end we have a complete list of the path the potential lead followed on the website.

Keep in mind that this tracking system is shown here as an example using ChatGPT’s UTM, but it can be done with absolutely anything, and it can also be customized very easily. We could even save the data in our WordPress dashboard and create our own analytics, more reliable, without sampling, and recording the data we care about.

If you don’t want to deal with the code or learn it, but want to have this implementation in your project in a simple and customizable way, it will soon be available at GEOhat LLM

This is how we would add our sequential Cookie system with PHP:
// Configuration
$utm_param_key = 'utm_source';
$utm_param_value = 'chatgpt.com';
$master_cookie = 'Track-ChatGPT';
$counter_cookie = 'track_chatgpt_counter';
$prefix = 'track-ChatGPT-';
$expiry_seconds = 30 * 60;
$max_cookies = 50;
$cookie_options = [
'expires' => time() + $expiry_seconds,
'path' => '/',
'secure' => is_ssl(),
'httponly' => false,
'samesite' => 'Lax',
];
$set_cookie = function(string $name, string $value, array $options) {
setcookie($name, $value, $options);
$_COOKIE[$name] = $value;
};
// Filter: avoid logging favicons, scripts, REST requests, etc.
$excluded_patterns = '#\.(ico|png|jpg|jpeg|gif|svg|webp|js|css|woff2?|ttf|eot)$#i';
$uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$is_valid_path = (
$method === 'GET' &&
!preg_match($excluded_patterns, $uri) &&
strpos($uri, '/wp-json/') === false
);
// Step 1: Should tracking be activated?
$activating = (
!isset($_COOKIE[$master_cookie]) &&
isset($_GET[$utm_param_key]) &&
$_GET[$utm_param_key] === $utm_param_value
);
// Step 2: Is it already active?
$active = (
isset($_COOKIE[$master_cookie]) &&
$_COOKIE[$master_cookie] === 'active'
);
// If it is activating or already active AND it's a valid page
if (($activating || $active) && $is_valid_path) {
$path = rawurlencode($_SERVER['REQUEST_URI']);
$count = isset($_COOKIE[$counter_cookie]) ? max(0, intval($_COOKIE[$counter_cookie])) : 0;
// Only if the limit hasn't been reached
if ($count < $max_cookies) {
$next = $count + 1;
$name = $prefix . str_pad($next, 2, '0', STR_PAD_LEFT);
$set_cookie($name, $path, $cookie_options);
$set_cookie($counter_cookie, (string) $next, $cookie_options);
$set_cookie($master_cookie, 'active', $cookie_options);
}
}

In this way, we register the journey the user is taking through our website in their browser.

Remember that you can see the Cookies that the website has set in your browser via DevTools > Application > Cookies.

So now the idea is that if the user came through ChatGPT, this information can be placed in the form, so that the company knows where the lead came from (this can also be applied with SEM/SEA UTMs or other marketing practices we implement) — basically, a little helper to remind the company where the lead originated from.

To make it appear like this (probably with some time and care, you can make it look nicer):

I’ll show you how to do it with Contact Form 7 or with your own submission system.

Adding tracking in Contact Form 7:

function asdrubal_get_chatgpt_steps(): array { $master = 'Track-ChatGPT'; $counter = 'track_chatgpt_counter'; $prefix = 'track-ChatGPT-'; if (empty($_COOKIE[$master]) || $_COOKIE[$master] !== 'activo') { return []; } $count = isset($_COOKIE[$counter]) ? max(0, (int)$_COOKIE[$counter]) : 0; if ($count === 0) return []; $steps = []; for ($i = 1; $i <= $count; $i++) { $name = $prefix . str_pad($i, 2, '0', STR_PAD_LEFT); if (empty($_COOKIE[$name])) continue; $url = rawurldecode($_COOKIE[$name]);
// Filter out URLs that are not real user navigation
if (preg_match('#/(wp-json|xmlrpc\.php|favicon\.ico|contact-form-7)/#', $url)) continue; if (preg_match('#\.(js|css|map|png|jpe?g|gif|svg|webp)(\?.*)?$#i', $url)) continue; $steps[] = esc_url($url); } return $steps; }
// SHORTCODE to display the route anywhere on the site with [chatgpt_route]
add_shortcode('chatgpt_route', function($atts){ $steps = asdrubal_get_chatgpt_steps(); if (!$steps) return '<div><strong>ChatGPT Route:</strong> (no data)</div>'; $html = '<div style="border:1px solid #ddd;padding:10px;border-radius:6px;margin:10px 0">'; $html .= '<strong>ChatGPT Route</strong>'; $html .= '<ol style="margin:6px 0 0 18px;padding:0">'; foreach ($steps as $url) { $html .= '<li><a href="'. $url .'">'. $url .'</a></li>'; } $html .= '</ol></div>'; return $html; });
// SPECIAL TAG to insert the route into Contact Form 7 emails
add_filter('wpcf7_special_mail_tags', function($output, $name, $html){ if ('_chatgpt_route_block' !== strtolower($name)) return $output; $steps = asdrubal_get_chatgpt_steps(); if (!$steps) { return $html ? '<div><strong>ChatGPT Route:</strong> (no data)</div>' : 'ChatGPT Route: (no data)'; } if ($html) { $out = '<div style="border:1px solid #ddd;padding:10px;border-radius:6px;margin:10px 0">'; $out .= '<strong>ChatGPT Route</strong>'; $out .= '<ol style="margin:6px 0 0 18px;padding:0">'; foreach ($steps as $url) { $out .= '<li><a href="'. $url .'">'. $url .'</a></li>'; } $out .= '</ol></div>'; return $out; } else { $lines = ["ChatGPT Route", "Sequence (" . count($steps) . " steps):"]; foreach ($steps as $i => $url) { $lines[] = ($i + 1) . ') ' . $url; } return implode("\n", $lines); } }, 10, 3);
// FORM TAG to add the data as hidden fields in Contact Form 7
add_action('wpcf7_init', function () { if (function_exists('wpcf7_add_form_tag')) { wpcf7_add_form_tag('chatgpt_route', 'asdrubal_cf7_chatgpt_route_form_tag_handler', ['name-attr' => false]); } }); function asdrubal_cf7_chatgpt_route_form_tag_handler($tag) { $steps = asdrubal_get_chatgpt_steps(); $origin = !empty($steps) ? $steps[0] : ''; $json = !empty($steps) ? wp_json_encode($steps, JSON_UNESCAPED_SLASHES) : '[]'; return sprintf( '<input type="hidden" name="chatgpt_origin_url" value="%s" />' . "\n" . '<input type="hidden" name="chatgpt_route" value="%s" />', esc_attr($origin), esc_attr($json) ); }

In a custom form:
// === Helping functions for ChatGPT tracking ===
function _as_fmt_duration($seconds) {
if ($seconds === null) return 's/d';
$seconds = max(0, (int)$seconds);
$h = floor($seconds / 3600);
$m = floor(($seconds % 3600) / 60);
$s = $seconds % 60;
return $h > 0 ? sprintf('%02d:%02d:%02d', $h, $m, $s) : sprintf('%02d:%02d', $m, $s);
}
/**
* Reads the tracking cookies and returns a structure with the origin URL,
* the sequence of steps, and the dwell time on each page (capped at 30 minutes).
*/
function _as_get_chatgpt_route_summary() {
$master_cookie = 'Track-ChatGPT';
$counter_cookie = 'track_chatgpt_counter';
$prefix = 'track-ChatGPT-';
$expiry_cap = 30 * 60; // Limit of 30 minutes
$out = [
'active' => (isset($_COOKIE[$master_cookie]) && $_COOKIE[$master_cookie] === 'activo'),
'origin_url' => '',
'steps' => [] // Format: ['i'=>1, 'url'=>'...', 'ts'=>int, 'dwell'=>int|null]
];
if (!$out['active']) return $out;
$count = isset($_COOKIE[$counter_cookie]) ? max(0, (int)$_COOKIE[$counter_cookie]) : 0;
if ($count === 0) return $out;
$steps = [];
for ($i = 1; $i <= $count; $i++) {
$name = $prefix . str_pad($i, 2, '0', STR_PAD_LEFT);
if (!isset($_COOKIE[$name])) continue;
$raw = $_COOKIE[$name];
$url = '';
$ts = null;
// Supports the new JSON value {url, ts} or the old format (URL only)
if ($raw && $raw[0] === '{') {
$data = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
$url = isset($data['url']) ? (string)$data['url'] : '';
$ts = isset($data['ts']) ? (int)$data['ts'] : null;
}
} else {
$url = rawurldecode($raw);
}
$steps[] = ['i'=>$i, 'url'=>$url, 'ts'=>$ts, 'dwell'=>null];
}
if (!$steps) return $out;
$out['origin_url'] = $steps[0]['url'];
// Calculates the dwell time between steps, limiting it to the defined maximum
$n = count($steps);
for ($k = 0; $k < $n; $k++) {
$cur = $steps[$k];
$next = $steps[$k+1] ?? null;
if (!empty($cur['ts']) && !empty($next['ts'])) {
$delta = max(0, $next['ts'] - $cur['ts']);
$steps[$k]['dwell'] = min($delta, $expiry_cap);
} elseif (!empty($cur['ts']) && $next === null) {
// Last page: calculates the time spent from entry until now
$delta = max(0, time() - $cur['ts']);
$steps[$k]['dwell'] = min($delta, $expiry_cap);
} else {
$steps[$k]['dwell'] = null; // Not enough data
}
}
$out['steps'] = $steps;
return $out;
}
/**
* Builds and returns the complete HTML block with the tracking summary,
* ready to be inserted into the body of an email.
*/
function _as_build_chatgpt_tracking_block_html() {
$s = _as_get_chatgpt_route_summary();
if (!$s['active']) {
return '<p><strong>ChatGPT Tracking: no data (no cookie/consent).</p>';
}
$html = '<h3 style="margin:16px 0 8px">URL origen de chatGPT</h3>';
$orig = htmlspecialchars($s['origin_url'] ?: 's/d', ENT_QUOTES, 'UTF-8');
$html .= $s['origin_url'] ? '<p><a href="'. $orig .'">'. $orig .'</a></p>' : '<p>s/d</p>';
$html .= '<h3 style="margin:16px 0 8px">Page sequence and dwell time</h3>';
$html .= '<ol style="padding-left:20px;margin:0">';
foreach ($s['steps'] as $step) {
$idx = str_pad((string)$step['i'], 2, '0', STR_PAD_LEFT);
$url = htmlspecialchars($step['url'] ?: 's/d', ENT_QUOTES, 'UTF-8');
$dwell = _as_fmt_duration($step['dwell']);
$html .= '<li style="margin:4px 0"><strong>'. $idx .')</strong> ';
$html .= $step['url'] ? '<a href="'. $url .'">'. $url .'</a>' : $url;
$html .= ' — dwell time: <em>'. $dwell .'</em></li>';
}
$html .= '</ol>';
return $html;
}

Remember that these are just examples. You can learn to program them yourself from the Technical SEO Master or ask an LLM for help to adapt the code to your case, testing little by little until you have it fully customized.

Dynamic POP-UP

We can make our website favor the ordering of certain products or pages, or even show specific CTAs and personalized banners if the user has accessed a particular page.

This is a fairly simple explanation of why, on airline websites, the same flight can appear more expensive after you’ve visited it, but not in incognito mode.

In this case, I’ve attached an example of someone visiting my master’s page, and after navigating 2 or 3 pages, a reminder is sent that there are still spots available.

Example of the code:
<?php
add_action('init', function () {
// ==== CONFIGURATION ====
$master_path = '/master-seo-tecnico/';
$cookie_visit_name = 'mst_master_visit';
$cookie_dismiss = 'mst_popup_dismissed';
$cookie_views = 'mst_views_after_master';
$cookie_threshold = 'mst_popup_threshold';
$visit_ttl_seconds = 60 * 60 * 24 * 30;
$dismiss_ttl_sec = 60 * 60 * 24 * 30;
$views_ttl_seconds = 60 * 60 * 24 * 30;
// Set a cookie when the user visits the master’s page
$current_path = parse_url((is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH);
if (trailingslashit($current_path) === $master_path) {
if (!isset($_COOKIE[$cookie_visit_name]) || $_COOKIE[$cookie_visit_name] !== '1') {
setcookie($cookie_visit_name, '1', [
'expires' => time() + $visit_ttl_seconds,
'path' => '/',
'secure' => is_ssl(),
'httponly' => false,
'samesite' => 'Lax',
]);
$_COOKIE[$cookie_visit_name] = '1';
}
setcookie($cookie_views, '0', [
'expires' => time() + $views_ttl_seconds,
'path' => '/',
'secure' => is_ssl(),
'httponly' => false,
'samesite' => 'Lax',
]);
$_COOKIE[$cookie_views] = '0';
}
// Popup script
add_action('wp_enqueue_scripts', function () use ($master_path, $cookie_visit_name, $cookie_dismiss, $cookie_views, $cookie_threshold, $dismiss_ttl_sec, $views_ttl_seconds) {
wp_register_script('mst-popup', false, [], null, true);
wp_enqueue_script('mst-popup');
$data = [
'masterPath' => $master_path,
'visitCookie' => $cookie_visit_name,
'dismissCookie'=> $cookie_dismiss,
'viewsCookie' => $cookie_views,
'thCookie' => $cookie_threshold,
'viewsTtl' => $views_ttl_seconds,
'dismissTtl' => $dismiss_ttl_sec,
'isMasterPage' => (trailingslashit(parse_url((is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], PHP_URL_PATH)) === $master_path),
'popup' => [
'title' => '¿Aún te interesa el Máster SEO Técnico?',
'msg' => 'Seguimos teniendo plazas abiertas, puedes reunirte conmigo y pedir información sin compromiso',
'cta' => 'Volver al Máster',
'close' => 'No mostrar de nuevo',
],
];
wp_add_inline_script('mst-popup', 'window.MST_POPUP = ' . wp_json_encode($data) . ';', 'before');
wp_add_inline_script('mst-popup', <<<JS
(function(){
var cfg = window.MST_POPUP || {};
if (!cfg || cfg.isMasterPage) return;
function getCookie(name){ var v=document.cookie.match('(?:^|; )'+name.replace(/([.$?*|{}()\\[\\]\\\\\\/\\+^])/g,'\\\\$1')+'=([^;]*)'); return v?decodeURIComponent(v[1]):null;}
function setCookie(name,value,seconds){var d=new Date(); d.setTime(d.getTime()+(seconds*1000)); document.cookie=name+'='+encodeURIComponent(value)+'; expires='+d.toUTCString()+'; path=/; samesite=Lax'+(location.protocol==='https:'?'; secure':'');}
if(getCookie(cfg.visitCookie)!=='1'||getCookie(cfg.dismissCookie)==='1')return;
if(location.pathname.replace(/\\/+$/,'/')===cfg.masterPath)return;
var th=parseInt(getCookie(cfg.thCookie)||'',10); if(!th||(th!==2&&th!==3)){th=(Math.random()<0.5?2:3); setCookie(cfg.thCookie,String(th),cfg.viewsTtl);}
var views=parseInt(getCookie(cfg.viewsCookie)||'0',10); views=isNaN(views)?0:views; views++; setCookie(cfg.viewsCookie,String(views),cfg.viewsTtl);
if(views<th)return; if(window.__mst_popup_shown)return; window.__mst_popup_shown=true;
var backdrop=document.createElement('div'); backdrop.id='mst-popup-backdrop';
var box=document.createElement('div'); box.id='mst-popup-box';
box.innerHTML=`<div class="mst-popup-title">${cfg.popup.title}</div><div class="mst-popup-msg">${cfg.popup.msg}</div><div class="mst-popup-actions"><a class="mst-popup-cta" href="${cfg.masterPath}">${cfg.popup.cta}</a><button type="button" class="mst-popup-close">${cfg.popup.close}</button></div>`;
backdrop.appendChild(box); document.body.appendChild(backdrop);
function closeForever(){setCookie(cfg.dismissCookie,'1',cfg.dismissTtl); backdrop.remove();}
box.querySelector('.mst-popup-close').addEventListener('click',function(e){e.preventDefault();closeForever();});
backdrop.addEventListener('click',function(e){if(e.target===backdrop){closeForever();}});
var css=document.createElement('style'); css.textContent=`
#mst-popup-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index:999999;}
#mst-popup-box{background:#fff;max-width:520px;width:90%;border-radius:14px;padding:22px 20px;box-shadow:0 10px 30px rgba(0,0,0,.2);font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Arial,sans-serif;}
.mst-popup-title{font-size:20px;font-weight:700;margin:0 0 8px;}
.mst-popup-msg{font-size:15px;margin:0 0 16px;}
.mst-popup-actions{display:flex;gap:10px;justify-content:flex-end;}
.mst-popup-cta{padding:10px 14px;border-radius:10px;text-decoration:none;background:var(--main);color:#fff;font-weight:600;}
.mst-popup-close{padding:10px 14px;border-radius:10px;border:1px solid #ddd;background:#f7f7f7;cursor:pointer;}
`; document.head.appendChild(css);
})();
JS
, 'after');
});
});

This would be a basic example of what I’ve adapted on this website. But you can use it to offer different prices, display a banner, or even show recommended articles/products to the user.

Contingency

Imagine that one day your website has a specific issue. Users weren’t able to submit contact forms, purchase a certain product, schedule a meeting, or subscribe to a newsletter.

It’s possible that the user will come back to the site after the incident, but they might think that this feature is still broken and won’t try again.

This is where you have the option of playing with cookies by injecting a daily cookie into the user’s browser.

The code to achieve this would be very simple:

<?php
$cookie_name = 'sesion-' . date('d-m-y');
$cookie_value = 'activo';
$expiry_time = time() + (60 * 60 * 24 * 60);
setcookie($cookie_name, $cookie_value, [
'expires' => $expiry_time,
'path' => '/',
'samesite' => 'Lax'
]);

Now, we could generate this effect if someone visited the site on the day when the issue we’re imagining occurred:

The code:
<?php
if (!isset($_COOKIE['sesion-22-09-25'])) return;
?>
<div id="popup" style="position:fixed;top:0;left:0;right:0;bottom:0;
background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:9999;">
<div style="background:#fff;padding:20px;border-radius:8px;max-width:400px;text-align:center;">
<p>On 22/09/2025 there was a maintenance issue and you weren’t able to subscribe.<br>Would you like to do it now?</p>
<button onclick="document.getElementById('popup').remove()">Close</button>
</div>
</div>

In this way, we can keep loading dynamic code depending on the day on which the user first visited the site.

Conclusion

It’s important to keep in mind that cookies can be implemented via PHP and also via JS, which means we can set cookies based on scroll position or interaction with specific elements. For example, we can assign cookies to users who like to click on videos, or distinguish users by the type of click they make in order to study their behavior.

You can apply gamification on your own website and make it much more interactive by combining programming languages with cookies themselves, improving not only your analytics with more precise data, but also personalizing the site so that it’s more pleasant and useful for users.

If you like this article, you would help me a lot by sharing my content:
Interested in Advanced SEO Training?

I currently offer advanced SEO training in Spanish. Would you like me to create an English version? Let me know!

Tell me you're interested
You might be interested in other articles:
SEO Articles
Usamos cookies para asegurar que te damos la mejor experiencia en nuestra web. Aquí tienes nuestra política de Cookies.