{"id":79,"date":"2026-07-05T19:41:11","date_gmt":"2026-07-05T19:41:11","guid":{"rendered":"https:\/\/everclif.com\/insights\/?p=79"},"modified":"2026-07-06T12:20:57","modified_gmt":"2026-07-06T12:20:57","slug":"chatgpt-ads-conversion-tracking","status":"publish","type":"post","link":"https:\/\/everclif.com\/insights\/chatgpt-ads-conversion-tracking\/","title":{"rendered":"ChatGPT Ads Conversion Tracking: The Setup That Finally Worked | EverClif"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"79\" class=\"elementor elementor-79\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d7d47b8 e-con-full e-flex e-con e-parent\" data-id=\"d7d47b8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f6e5320 elementor-widget__width-initial elementor-widget elementor-widget-html\" data-id=\"f6e5320\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\n\n:root {\n    --primary: #000080;\n    --accent:  #1E90FF;\n    --white:   #ffffff;\n    --light:   #F5F6F7;\n    --dark:    #333333;\n    --amber:      #F59E0B;\n    --amber-dark: #D97706;\n    --amber-soft: rgba(245, 158, 11, 0.12);\n}\n\n.ec-blog-post {\n    font-family: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n    color: var(--dark);\n    line-height: 1.6;\n    font-variation-settings: 'wght' 400;\n}\n\n.ec-blog-post .container {\n    max-width: 1200px;\n    margin: 0 auto;\n    padding: 0 24px;\n}\n\n\/* \u2500\u2500 Hero \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.ec-blog-post .blog-hero {\n    position: relative;\n    padding: 150px 0 70px;\n    overflow: hidden;\n    background: linear-gradient(135deg, var(--primary) 0%, #14207A 50%, #0E2E8F 100%);\n}\n\n.ec-blog-post .blog-hero-inner {\n    display: grid;\n    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);\n    gap: 48px;\n    align-items: center;\n}\n\n.ec-blog-post .blog-hero-text {\n    position: relative;\n    z-index: 1;\n}\n\n.ec-blog-post .blog-hero-media { width: 100%; }\n\n.ec-blog-post .blog-hero-img {\n    width: 100%;\n    aspect-ratio: 5 \/ 3;\n    object-fit: cover;\n    display: block;\n    border-radius: 16px;\n    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);\n}\n\n.ec-blog-post .blog-hero-eyebrow {\n    display: inline-block;\n    font-size: 13px;\n    font-weight: 700;\n    letter-spacing: 0.5px;\n    text-transform: uppercase;\n    color: var(--white);\n    background: rgba(245, 158, 11, 0.22);\n    border: 1px solid rgba(245, 158, 11, 0.55);\n    padding: 6px 14px;\n    border-radius: 99px;\n    margin-bottom: 20px;\n}\n\n.ec-blog-post .blog-hero-title {\n    font-size: 40px;\n    font-weight: 700;\n    font-variation-settings: 'wght' 700;\n    color: var(--white);\n    line-height: 1.25;\n    margin-bottom: 16px;\n}\n\n.ec-blog-post .blog-hero-meta {\n    font-size: 15px;\n    color: rgba(255, 255, 255, 0.75);\n}\n\n\/* \u2500\u2500 Layout: TOC + content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.ec-blog-post .blog-body {\n    padding: 64px 0 40px;\n    background: var(--white);\n}\n\n.ec-blog-post .blog-layout {\n    display: grid;\n    grid-template-columns: 260px minmax(0, 1fr);\n    gap: 64px;\n    align-items: start;\n}\n\n.ec-blog-post .blog-toc {\n    position: sticky;\n    top: 100px;\n    align-self: start;\n    max-height: calc(100vh - 130px);\n    overflow-y: auto;\n}\n\n.ec-blog-post .blog-toc-label {\n    font-size: 12px;\n    font-weight: 700;\n    letter-spacing: 0.6px;\n    text-transform: uppercase;\n    color: var(--accent);\n    margin-bottom: 14px;\n}\n\n.ec-blog-post .blog-toc-list {\n    list-style: none;\n    border-left: 2px solid rgba(30, 144, 255, 0.18);\n}\n\n.ec-blog-post .toc-link {\n    display: block;\n    padding: 7px 0 7px 16px;\n    margin-left: -2px;\n    border-left: 2px solid transparent;\n    font-size: 14.5px;\n    color: var(--dark);\n    text-decoration: none;\n    line-height: 1.4;\n    transition: color 0.2s ease, border-color 0.2s ease;\n}\n\n.ec-blog-post .toc-link--sub { padding-left: 30px; font-size: 13.5px; opacity: 0.85; }\n\n.ec-blog-post .toc-link:hover { color: var(--primary); }\n\n.ec-blog-post .toc-link.is-active {\n    color: var(--primary);\n    font-weight: 700;\n    border-left-color: var(--amber);\n}\n\n\/* \u2500\u2500 Article content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.ec-blog-post .blog-content {\n    max-width: 720px;\n    font-size: 17px;\n    line-height: 1.8;\n    color: var(--dark);\n}\n\n.ec-blog-post .blog-content > p { margin-bottom: 22px; }\n\n.ec-blog-post .blog-content h2 {\n    font-size: 30px;\n    font-weight: 700;\n    font-variation-settings: 'wght' 700;\n    color: var(--primary);\n    margin: 52px 0 18px;\n    line-height: 1.3;\n}\n\n.ec-blog-post .blog-content h2:first-of-type { margin-top: 36px; }\n\n.ec-blog-post .blog-content h3 {\n    font-size: 22px;\n    font-weight: 700;\n    font-variation-settings: 'wght' 700;\n    color: var(--primary);\n    margin: 38px 0 14px;\n    line-height: 1.35;\n}\n\n.ec-blog-post .blog-content strong { font-weight: 700; }\n\n.ec-blog-post .blog-content em { color: var(--primary); font-style: italic; }\n\n.ec-blog-post .blog-content ul {\n    margin: 0 0 22px 0;\n    padding-left: 22px;\n}\n\n.ec-blog-post .blog-content ul li {\n    margin-bottom: 10px;\n    line-height: 1.7;\n}\n\n.ec-blog-post .blog-content code {\n    font-family: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', Consolas, monospace;\n    font-size: 14.5px;\n    background: rgba(30, 144, 255, 0.08);\n    color: var(--primary);\n    padding: 2px 6px;\n    border-radius: 4px;\n    border: 1px solid rgba(30, 144, 255, 0.15);\n}\n\n.ec-blog-post .blog-content pre {\n    background: #0F1B3D;\n    border-radius: 10px;\n    padding: 22px 24px;\n    margin: 24px 0 28px;\n    overflow-x: auto;\n    box-shadow: 0 4px 18px rgba(0, 0, 128, 0.18);\n}\n\n.ec-blog-post .blog-content pre code {\n    font-family: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', Consolas, monospace;\n    font-size: 13.5px;\n    line-height: 1.7;\n    color: #A8D8FF;\n    background: none;\n    border: none;\n    padding: 0;\n    white-space: pre;\n}\n\n\/* \u2500\u2500 In-article CTA banner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.ec-blog-post .blog-cta-banner {\n    display: flex;\n    align-items: center;\n    gap: 28px;\n    background: linear-gradient(135deg, var(--primary) 0%, #14207A 50%, #0E2E8F 100%);\n    border-radius: 16px;\n    padding: 32px;\n    margin: 44px 0 48px;\n    box-shadow: 0 10px 30px rgba(0, 0, 128, 0.22);\n}\n\n.ec-blog-post .blog-cta-img {\n    width: 96px;\n    height: 96px;\n    border-radius: 50%;\n    object-fit: cover;\n    border: 3px solid var(--amber);\n    flex-shrink: 0;\n}\n\n.ec-blog-post .blog-cta-body { flex: 1; }\n\n.ec-blog-post .blog-cta-text {\n    color: var(--white);\n    font-size: 17px;\n    line-height: 1.6;\n    margin-bottom: 16px;\n}\n\n.ec-blog-post .blog-cta-btn {\n    display: inline-block;\n    padding: 11px 26px;\n    font-size: 16px;\n    font-weight: 700;\n    color: var(--primary);\n    background: linear-gradient(135deg, #FBBF45 0%, var(--amber) 100%);\n    border: 2px solid var(--amber);\n    border-radius: 6px;\n    text-decoration: none;\n    box-shadow: 0 6px 22px rgba(245, 158, 11, 0.4);\n    transition: all 0.3s ease;\n}\n\n.ec-blog-post .blog-cta-btn:hover {\n    transform: translateY(-2px);\n    box-shadow: 0 10px 30px rgba(245, 158, 11, 0.55);\n}\n\n\/* \u2500\u2500 FAQ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n.ec-blog-post .blog-faq {\n    background: var(--light);\n    padding: 80px 0;\n}\n\n.ec-blog-post .blog-faq-title {\n    font-size: 34px;\n    font-weight: 700;\n    font-variation-settings: 'wght' 700;\n    color: var(--primary);\n    text-align: center;\n    margin-bottom: 40px;\n}\n\n.ec-blog-post .blog-faq-item {\n    background: var(--white);\n    border: 1px solid rgba(30, 144, 255, 0.18);\n    border-radius: 12px;\n    overflow: hidden;\n    box-shadow: 0 2px 10px rgba(30, 144, 255, 0.06);\n    transition: border-color 0.2s ease, box-shadow 0.2s ease;\n    margin-bottom: 14px;\n}\n\n.ec-blog-post .blog-faq-item.is-open {\n    border-color: var(--amber);\n    box-shadow: 0 6px 18px rgba(245, 158, 11, 0.18);\n}\n\n.ec-blog-post .blog-faq-question {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 16px;\n    background: none;\n    border: none;\n    cursor: pointer;\n    text-align: left;\n    padding: 20px 24px;\n    font-size: 16px;\n    font-weight: 600;\n    color: var(--primary);\n    font-family: inherit;\n}\n\n.ec-blog-post .blog-faq-toggle {\n    flex-shrink: 0;\n    width: 26px;\n    height: 26px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    border-radius: 50%;\n    background: var(--amber-soft);\n    color: var(--amber-dark);\n    font-size: 18px;\n    font-weight: 700;\n    transition: transform 0.25s ease;\n}\n\n.ec-blog-post .blog-faq-item.is-open .blog-faq-toggle { transform: rotate(45deg); }\n\n.ec-blog-post .blog-faq-answer {\n    max-height: 0;\n    overflow: hidden;\n    transition: max-height 0.35s ease;\n}\n\n.ec-blog-post .blog-faq-item.is-open .blog-faq-answer { max-height: 800px; }\n\n.ec-blog-post .blog-faq-answer p {\n    padding: 0 24px 22px;\n    color: var(--dark);\n    font-size: 15.5px;\n    line-height: 1.7;\n}\n\n.ec-blog-post .blog-faq-answer code {\n    font-family: 'SF Mono', 'Fira Code', Consolas, monospace;\n    font-size: 13.5px;\n    background: rgba(30, 144, 255, 0.08);\n    color: var(--primary);\n    padding: 2px 5px;\n    border-radius: 4px;\n}\n\n\/* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n@media (max-width: 900px) {\n    .ec-blog-post .blog-layout {\n        grid-template-columns: 1fr;\n        gap: 32px;\n    }\n    .ec-blog-post .blog-toc {\n        position: static;\n        max-height: none;\n        order: -1;\n        border: 1px solid rgba(30, 144, 255, 0.18);\n        border-radius: 12px;\n        padding: 18px 20px;\n    }\n    .ec-blog-post .blog-toc-list { max-height: 220px; overflow-y: auto; }\n    .ec-blog-post .blog-hero-inner { grid-template-columns: 1fr; gap: 32px; }\n    .ec-blog-post .blog-hero-media { max-width: 480px; margin: 0 auto; }\n    .ec-blog-post .blog-hero-title { font-size: 32px; }\n}\n\n@media (max-width: 600px) {\n    .ec-blog-post .blog-hero { padding: 140px 0 48px; }\n    .ec-blog-post .blog-cta-banner { flex-direction: column; text-align: center; }\n    .ec-blog-post .blog-faq-title { font-size: 26px; }\n}\n<\/style>\n\n<div class=\"ec-blog-post\">\n\n    <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n         HERO\n         \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n    <header class=\"blog-hero\">\n        <div class=\"container blog-hero-inner\">\n            <div class=\"blog-hero-text\">\n                <span class=\"blog-hero-eyebrow\">Performance Marketing<\/span>\n                <h1 class=\"blog-hero-title\">ChatGPT Ads Conversion Tracking: The Setup That Finally Worked for Me<\/h1>\n                <p class=\"blog-hero-meta\">Anirban Saha &middot; 6 July 2026 &middot; <span id=\"ec-reading-time\">6<\/span> minutes read<\/p>\n            <\/div>\n            <div class=\"blog-hero-media\">\n                <img decoding=\"async\" src=\"https:\/\/everclif.com\/insights\/wp-content\/uploads\/2026\/07\/chatgpt-ads-conversion-feature.png\" alt=\"ChatGPT Ads Conversion Tracking\" class=\"blog-hero-img\">\n            <\/div>\n        <\/div>\n    <\/header>\n\n    <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n         ARTICLE BODY: TOC (left) + content (right)\n         \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n    <section class=\"blog-body\">\n        <div class=\"container blog-layout\">\n\n            <aside class=\"blog-toc\">\n                <p class=\"blog-toc-label\">On this page<\/p>\n                <nav aria-label=\"Table of contents\">\n                    <ul class=\"blog-toc-list\">\n                        <li><a href=\"#why-this-matters\" class=\"toc-link\" data-toc-level=\"2\">Why ChatGPT Ads tracking trips people up<\/a><\/li>\n                        <li><a href=\"#two-steps\" class=\"toc-link\" data-toc-level=\"2\">Two steps, nothing exotic<\/a><\/li>\n                        <li><a href=\"#step-1-data-source\" class=\"toc-link\" data-toc-level=\"2\">Step 1: Set up the data source<\/a><\/li>\n                        <li><a href=\"#step-2-conversion-event\" class=\"toc-link\" data-toc-level=\"2\">Step 2: Set up the conversion event<\/a><\/li>\n                        <li><a href=\"#codex-route\" class=\"toc-link\" data-toc-level=\"2\">The Codex route that unblocked me<\/a><\/li>\n                        <li><a href=\"#codex-caught\" class=\"toc-link toc-link--sub\" data-toc-level=\"3\">Three things Codex caught<\/a><\/li>\n                        <li><a href=\"#validation\" class=\"toc-link\" data-toc-level=\"2\">Validation: four layers of checks<\/a><\/li>\n                        <li><a href=\"#what-fixed-it\" class=\"toc-link\" data-toc-level=\"2\">The thing that actually fixed it<\/a><\/li>\n                        <li><a href=\"#faq\" class=\"toc-link\" data-toc-level=\"2\">FAQ<\/a><\/li>\n                    <\/ul>\n                <\/nav>\n            <\/aside>\n\n            <article class=\"blog-content\">\n\n                <p>OpenAI Ads is new, thin, and a little fiddly. Conversion tracking is where most people get stuck. Here is the exact process that cleared the &ldquo;no recent conversion events&rdquo; warning for me, step by step.<\/p>\n\n                <h2 id=\"why-this-matters\">Why ChatGPT Ads conversion tracking trips people up<\/h2>\n                <p>Performance marketers have been waiting for ChatGPT Ads, or OpenAI Ads, for some time now. It sat in talks and speculation for a long while, and it finally arrived in May. These are still early days. It still looks pretty thin and nascent to anyone who has been running Google Ads, LinkedIn Ads, or Meta Ads for a few years.<\/p>\n                <p>Setting up campaigns, ad groups, and ads is fairly straightforward, apart from the context hints (that&rsquo;s a topic for another day). Where a lot of people get stuck is conversion tracking. OpenAI does provide a step-by-step process for it, and even with that, I had my own share of struggles.<\/p>\n                <p>I tried a few things. I tried the events stream. There is a &ldquo;start polling&rdquo; option that did nothing for me. The warning stayed put, telling me no events were set up, and at one point flagging two events with parameters that didn&rsquo;t match. I know several people who have hit this exact wall, so let me put down the process that finally worked. There may be other ways that work for you, but this is definitely one of them.<\/p>\n\n                <h2 id=\"two-steps\">Two steps, nothing exotic<\/h2>\n                <p>Setting up conversions has two parts: setting up the data source, and then setting up the conversion event. There&rsquo;s nothing new here conceptually. It is the same shape as any CPC platform you&rsquo;ve used before. Honestly, the data source part is quite uneventful. The conversion event is where the friction lives.<\/p>\n\n                <!-- CTA banner at ~25% scroll -->\n                <aside class=\"blog-cta-banner\">\n                    <img decoding=\"async\" src=\"https:\/\/everclif.com\/insights\/wp-content\/uploads\/2026\/07\/founder.jpg\" alt=\"Anirban Saha, Founder of EverClif\" class=\"blog-cta-img\" width=\"96\" height=\"96\">\n                    <div class=\"blog-cta-body\">\n                        <p class=\"blog-cta-text\">EverClif runs paid campaigns end-to-end across ad platforms like ChatGPT Ads with business impact & efficiency as goals. We can set up and run your ChatGPT Ads campaigns.<\/p>\n                        <a href=\"https:\/\/calendly.com\/anirban-everclif\/30min\" class=\"blog-cta-btn\" target=\"_blank\" rel=\"noopener noreferrer\">Book a Call<\/a>\n                    <\/div>\n                <\/aside>\n\n                <h2 id=\"step-1-data-source\">Step 1: Set up the data source (the base pixel)<\/h2>\n                <p>In Ads Manager, go to <strong>Tools &rarr; Conversions<\/strong>. There&rsquo;s a <strong>Create<\/strong> button. Click it and create a data source. OpenAI gives you a snippet that needs to sit in the <code>&lt;head&gt;<\/code> section of every page (or every landing page) of your site. You can do this a few different ways. I used Google Tag Manager.<\/p>\n                <p>Here&rsquo;s how I set it up in GTM:<\/p>\n                <ul>\n                    <li>Create a new tag. I named mine <code>openai_ads_setup_code<\/code>.<\/li>\n                    <li>Tag type: <strong>Custom HTML<\/strong>.<\/li>\n                    <li>Paste the base code and add your <strong>Pixel ID<\/strong>.<\/li>\n                    <li>Set the trigger to <strong>Initialization &ndash; All Pages<\/strong>.<\/li>\n                    <li>Run a <strong>Preview<\/strong>. At page load, the tag should show as fired.<\/li>\n                    <li>Submit and save.<\/li>\n                <\/ul>\n                <p>The base pixel looks like this (swap in your own Pixel ID):<\/p>\n                <pre><code>&lt;script&gt;\n!function(w,d,s,u){if(w.oaiq)return;var q=function(){q.q.push(arguments)};q.q=[];w.oaiq=q;var j=d.createElement(s);j.async=1;j.src=u;var f=d.getElementsByTagName(s)[0];f.parentNode.insertBefore(j,f)}(window,document,\"script\",\"https:\/\/bzrcdn.openai.com\/sdk\/oaiq.min.js\");\noaiq(\"init\",{pixelId:\"YOUR-PIXEL-ID\"});\n&lt;\/script&gt;<\/code><\/pre>\n                <p>If the tag isn&rsquo;t firing, cross-check three things: the Pixel ID, the code itself, and (most commonly the culprit) whether you&rsquo;ve set the trigger to Initialization &ndash; All Pages rather than a normal page-view trigger.<\/p>\n\n                <h2 id=\"step-2-conversion-event\">Step 2: Set up the conversion event<\/h2>\n                <p>There are multiple event types you can set up: <em>registration completed<\/em>, <em>lead created<\/em>, <em>app installed<\/em>, <em>app opened<\/em>, and plenty more. I went with <strong>lead created<\/strong>.<\/p>\n                <p>In my case, the flow is simple. The user sees the ad in ChatGPT, clicks it, and lands on a landing page. On that page there&rsquo;s a short form: they drop in their email and submit. In GTM, I already had an event set up for a successful form submission, so I had the trigger side covered.<\/p>\n                <p>OpenAI provides a script you can add as a Custom HTML tag in GTM, and in theory you set the right trigger for a successful form submit and it should just work. For me, it didn&rsquo;t. That&rsquo;s where the newer Codex route came in.<\/p>\n\n                <h2 id=\"codex-route\">The Codex route that unblocked me<\/h2>\n                <p>There&rsquo;s an option that recently showed up in Ads Manager where you can create the conversion event using ChatGPT Codex. Here&rsquo;s how that played out:<\/p>\n                <ul>\n                    <li>Click the &ldquo;set up with Codex&rdquo; option in Ads Manager.<\/li>\n                    <li>If you don&rsquo;t have Codex installed, install it. It adds a plugin called <code>openai-ads-conversions<\/code>.<\/li>\n                    <li>Tell Codex your constraints. I told it plainly: I don&rsquo;t have access to the website, the server side, or any code, but I can implement through Google Tag Manager, so give me steps accordingly.<\/li>\n                    <li>Codex then handed me GTM-specific steps and a code snippet to add as a Custom HTML tag.<\/li>\n                    <li>I also gave Codex the base code I&rsquo;d already implemented, so it had the full picture.<\/li>\n                <\/ul>\n\n                <h3 id=\"codex-caught\">The three things Codex caught that mattered<\/h3>\n                <p>A few details from Codex made the difference between a tag that fires and a conversion that actually registers:<\/p>\n                <ul>\n                    <li><strong>The <code>debug: true<\/code> flag.<\/strong> The script I&rsquo;d copied from Ads Manager had <code>debug: true<\/code> in it. Codex confirmed that&rsquo;s fine for testing and told me to keep it while validating in GTM Preview and the browser console, then remove it before pushing to production.<\/li>\n                    <li><strong>The two parameters that have to match.<\/strong> In the conversion event code there&rsquo;s a parameter under <code>oaiq<\/code> with a main value and a <code>type<\/code>. Those two are critical and they have to match what you configured. This is exactly the &ldquo;parameters that didn&rsquo;t match&rdquo; warning I kept seeing.<\/li>\n                    <li><strong>Load order.<\/strong> Codex made sure the base code loads before the conversion event code. My original line only worked if <code>oaiq<\/code> was already available at that exact moment. So it added a <code>window.oaiq &amp;&amp;<\/code> guard to prevent an error if the lead event fired before the base pixel had initialised. It shouldn&rsquo;t normally happen, but I added it anyway. Codex also suggested tag sequencing, which I didn&rsquo;t end up implementing.<\/li>\n                <\/ul>\n\n                <p>The lead event tag ended up looking like this:<\/p>\n                <pre><code>&lt;script&gt;\nwindow.oaiq &amp;&amp; oaiq(\"measure\", \"lead_created\", {\n  type: \"customer_action\"\n});\n&lt;\/script&gt;<\/code><\/pre>\n                <p>The trigger is the successful form submission event you already have in GTM. In my setup the tags line up like this:<\/p>\n                <ul>\n                    <li><code>openai_ads_setup_code<\/code> &ndash; trigger: Initialization \/ All Pages.<\/li>\n                    <li><code>OpenAI_ads_Leads<\/code> (the <code>lead_created<\/code> event) &ndash; trigger: successful form submit only.<\/li>\n                <\/ul>\n\n                <h2 id=\"validation\">Validation: four layers of checks<\/h2>\n                <p>This is the part I wouldn&rsquo;t skip past too quickly if I were you, so slow down here. There are multiple layers of checks and each one matters.<\/p>\n                <ul>\n                    <li><strong>GTM Preview.<\/strong> Both tags should fire: the base code at page load, and the conversion event on form submit.<\/li>\n                    <li><strong>Browser Network tab.<\/strong> Filter for <code>openai<\/code>, <code>bzr<\/code>, or <code>oaiq<\/code>. Confirm the SDK loads from <code>bzrcdn.openai.com<\/code>.<\/li>\n                    <li><strong>Live landing page test.<\/strong> Go to the actual published landing page and submit a test lead. In the Network tab, confirm the request fires again to <code>bzr.openai.com\/v1\/sdk\/events<\/code>.<\/li>\n                    <li><strong>Inspect the payload.<\/strong> Click the request and open the payload. It should contain the exact lead type you selected. In my case that was <code>&quot;type&quot;: &quot;lead_created&quot;<\/code>.<\/li>\n                <\/ul>\n                <p>A healthy request payload looks like this:<\/p>\n                <pre><code>[\n  {\n    \"type\": \"lead_created\",\n    \"timestamp_ms\": 1782541528292,\n    \"id\": \"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n    \"source_url\": \"https:\/\/your-landing-page.com\/lp\/example\",\n    \"data\": {\n      \"type\": \"customer_action\"\n    }\n  }\n]<\/code><\/pre>\n\n                <h2 id=\"what-fixed-it\">The thing that actually fixed it<\/h2>\n                <p>Here&rsquo;s the honest bit. Initially the payload wasn&rsquo;t coming through, and that&rsquo;s why everything was silently failing. The tags fired, the SDK loaded, and still nothing registered. What broke the logjam was going back and removing <code>debug: true<\/code>, doing a hard refresh, filling out the form again, and re-checking. That&rsquo;s when I finally saw the payload carrying <code>&quot;type&quot;: &quot;lead_created&quot;<\/code>.<\/p>\n                <p>Then I waited. The &ldquo;no recent conversion events&rdquo; warning references the last 24 complete UTC hours, so it doesn&rsquo;t clear instantly. A couple of hours after my live test, the warning on the Ads Manager conversions tab was gone, and conversion events started showing up in the OpenAI Ads Manager Conversions tab.<\/p>\n                <p>If you&rsquo;re stuck at the same warning, the sequence that worked for me was: valid base pixel on all pages, a matching conversion event on the real submit, remove <code>debug: true<\/code>, hard refresh, confirm the payload on a live submission, then give it time to process. That was it.<\/p>\n\n            <\/article>\n        <\/div>\n    <\/section>\n\n    <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n         FAQ \u2014 full-width section, visually distinct from article\n         \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n    <section class=\"blog-faq\" id=\"faq\">\n        <div class=\"container\">\n            <h2 class=\"blog-faq-title\">Frequently Asked Questions<\/h2>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    How does setting up conversion tracking actually help my ChatGPT Ads?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>Without conversion tracking, OpenAI Ads only sees clicks. It has no idea which of those clicks turned into a lead or a sale. ChatGPT Ads still doesn&rsquo;t have a conversion objective &mdash; the best your campaign can optimise for right now is clicks. The conversions objective is listed as &ldquo;Coming soon&rdquo; in Ads Manager. Having conversion tracking in place now means you can see which ads are performing, and when the conversion objective eventually launches, you&rsquo;ll already have data to seed it with.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    Is using Codex the only way to set up the conversion event?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>No. Codex is one path, and it happens to be the one that unblocked me, mostly because it caught the small details around <code>debug: true<\/code>, matching parameters, and load order. You can also take the standard script OpenAI provides in Ads Manager and place it yourself, whether that&rsquo;s directly in your site&rsquo;s code or as a Custom HTML tag in Google Tag Manager. If your form submission trigger is solid and the pixel parameters match, the manual route works fine. Codex is a convenience for getting the exact snippet and catching mistakes, not a hard requirement.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    Do I need developer or server access to track ChatGPT Ads conversions?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>Not for the browser pixel. The entire setup described here runs through Google Tag Manager without touching site or server code, which is exactly the constraint I was working under. Server-side tracking through a Conversions API is a separate, more advanced option that does need a secret key handled on your server, so it shouldn&rsquo;t be placed in browser-side GTM.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    Why does the &ldquo;no recent conversion events&rdquo; warning stay even after my tags fire?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>A firing tag isn&rsquo;t the same as a received, normalised event. The warning looks at whether OpenAI has processed conversion events in the last 24 complete UTC hours. Common reasons it lingers: the GTM container wasn&rsquo;t actually published to the live site, an ad blocker or consent setting stopped the tag for real users, the event fired in Preview but not on the live container, or the payload didn&rsquo;t carry the correct event type. Once a real live submission sends a valid payload, give it a few hours to clear.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    How long before conversions appear in OpenAI Ads Manager?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>In my experience it was a couple of hours after a valid live test, not instant. Because the warning is tied to complete UTC reporting windows, allow for processing time before assuming something is broken. If it&rsquo;s still empty roughly a full day after a confirmed live event with a valid payload, that&rsquo;s when it&rsquo;s worth re-checking your publish status and triggers.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"blog-faq-item\">\n                <button class=\"blog-faq-question\" aria-expanded=\"false\">\n                    Which conversion event type should I choose?\n                    <span class=\"blog-faq-toggle\" aria-hidden=\"true\">+<\/span>\n                <\/button>\n                <div class=\"blog-faq-answer\">\n                    <p>Pick the one that matches the actual action you&rsquo;re paying to drive. If your goal is form fills on a landing page, <code>lead_created<\/code> is the natural fit. If you&rsquo;re driving purchases, registrations, or app events, use the matching type instead. The important thing is that the event type in your code matches the event type configured in Ads Manager, because a mismatch there is one of the quiet reasons tracking appears to fail.<\/p>\n                <\/div>\n            <\/div>\n\n        <\/div>\n    <\/section>\n\n<\/div><!-- \/.ec-blog-post -->\n\n<script>\n(function () {\n    function initBlogTemplate() {\n        \/\/ \u2500\u2500 FAQ accordion \u2500\u2500\n        document.querySelectorAll('.ec-blog-post .blog-faq-question').forEach(function (btn) {\n            btn.addEventListener('click', function () {\n                var item = btn.closest('.blog-faq-item');\n                var isOpen = item.classList.contains('is-open');\n                document.querySelectorAll('.ec-blog-post .blog-faq-item.is-open').forEach(function (openItem) {\n                    if (openItem !== item) {\n                        openItem.classList.remove('is-open');\n                        openItem.querySelector('.blog-faq-question').setAttribute('aria-expanded', 'false');\n                    }\n                });\n                item.classList.toggle('is-open', !isOpen);\n                btn.setAttribute('aria-expanded', String(!isOpen));\n            });\n        });\n\n        \/\/ \u2500\u2500 Reading time \u2500\u2500\n        var readingTimeEl = document.getElementById('ec-reading-time');\n        var articleEl = document.querySelector('.ec-blog-post .blog-content');\n        if (readingTimeEl && articleEl) {\n            var words = articleEl.textContent.trim().split(\/\\s+\/).filter(Boolean).length;\n            readingTimeEl.textContent = String(Math.max(1, Math.ceil(words \/ 200)));\n        }\n\n        \/\/ \u2500\u2500 TOC scroll-spy \u2500\u2500\n        var tocLinks = Array.from(document.querySelectorAll('.ec-blog-post .toc-link'));\n        if (!tocLinks.length) return;\n\n        var targets = tocLinks.map(function (link) {\n            var id = link.getAttribute('href').slice(1);\n            var el = document.getElementById(id);\n            return el ? { link: link, el: el } : null;\n        }).filter(Boolean);\n\n        if (!targets.length) return;\n\n        function setActive(id) {\n            tocLinks.forEach(function (link) {\n                link.classList.toggle('is-active', link.getAttribute('href') === '#' + id);\n            });\n        }\n\n        var observer = new IntersectionObserver(function (entries) {\n            var visible = entries\n                .filter(function (e) { return e.isIntersecting; })\n                .sort(function (a, b) { return a.boundingClientRect.top - b.boundingClientRect.top; });\n            if (visible.length) setActive(visible[0].target.id);\n        }, { rootMargin: '-120px 0px -65% 0px', threshold: 0 });\n\n        targets.forEach(function (t) { observer.observe(t.el); });\n        setActive(targets[0].el.id);\n    }\n\n    if (document.readyState === 'loading') {\n        document.addEventListener('DOMContentLoaded', initBlogTemplate);\n    } else {\n        initBlogTemplate();\n    }\n})();\n<\/script>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>ChatGPT Ads stuck on &#8216;no recent conversion events&#8217;? Here&#8217;s the exact GTM pixel, event setup, and validation steps that finally fixed it.<\/p>\n","protected":false},"author":1,"featured_media":92,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-79","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/posts\/79","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/comments?post=79"}],"version-history":[{"count":14,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/posts\/79\/revisions"}],"predecessor-version":[{"id":102,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/posts\/79\/revisions\/102"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/media\/92"}],"wp:attachment":[{"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/media?parent=79"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/categories?post=79"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/everclif.com\/insights\/wp-json\/wp\/v2\/tags?post=79"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}