Shopify Age Verification Popup

A date-of-birth or yes/no age gate, remembered for repeat visits, scoped to the products that need it.

Describe the result you need. AI will set up the tool and ask for any missing details.

Configure with AI

Enter to submit · Shift + Enter for a new line

Sent to AI. Leave out passwords and private customer data.

Your details

Rule
Text
Behavior
days

Your snippet file (snippets/age-verification.liquid)

age-verification.liquid
{%- comment -%}
  Cookie-based age gate. Client-side only: a good-faith check, not identity verification.
{%- endcomment -%}
{%- assign ea_show_gate = true -%}
{%- if ea_show_gate -%}
  {%- style -%}
  .ea-agegate{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.75);display:flex;align-items:center;justify-content:center;padding:1rem}
  .ea-agegate[hidden]{display:none}
  .ea-agegate__card{background:#fff;border-radius:12px;max-width:380px;width:100%;padding:1.75rem;text-align:center}
  .ea-agegate__heading{margin:0 0 .5rem;font-size:1.25em}
  .ea-agegate__body{margin:0 0 1.25rem;color:#555;font-size:14px}
  .ea-agegate__dob{display:flex;gap:.5rem;justify-content:center;margin-bottom:1rem}
  .ea-agegate__dob select{font:inherit;padding:.5em;border:1px solid #ccc;border-radius:6px}
  .ea-agegate__actions{display:flex;gap:.5rem;justify-content:center}
  .ea-agegate__btn{padding:.65em 1.4em;border-radius:6px;border:0;font:inherit;font-weight:600;cursor:pointer}
  .ea-agegate__btn--primary{background:#111;color:#fff}
  .ea-agegate__btn--secondary{background:#eee;color:#111}
  .ea-agegate__error{color:#b3352c;font-size:13px;margin-top:.75rem}
  .ea-agegate__error[hidden]{display:none}
  {%- endstyle -%}
  <div id="ea-age-gate" class="ea-agegate" data-mode="dob" data-min-age="18" data-cookie-days="30" data-decline="close" data-redirect="https://www.google.com" hidden>
    <div class="ea-agegate__card">
      <h2 class="ea-agegate__heading">Are you old enough?</h2>
      <p class="ea-agegate__body">You must be of legal age to view this site.</p>
      <form>
      <div class="ea-agegate__dob">
        <select name="ea-day" aria-label="Day"><option value="">Day</option><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option><option value="24">24</option><option value="25">25</option><option value="26">26</option><option value="27">27</option><option value="28">28</option><option value="29">29</option><option value="30">30</option><option value="31">31</option></select>
        <select name="ea-month" aria-label="Month"><option value="">Month</option><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option></select>
        <select name="ea-year" aria-label="Year"><option value="">Year</option><option value="2026">2026</option><option value="2025">2025</option><option value="2024">2024</option><option value="2023">2023</option><option value="2022">2022</option><option value="2021">2021</option><option value="2020">2020</option><option value="2019">2019</option><option value="2018">2018</option><option value="2017">2017</option><option value="2016">2016</option><option value="2015">2015</option><option value="2014">2014</option><option value="2013">2013</option><option value="2012">2012</option><option value="2011">2011</option><option value="2010">2010</option><option value="2009">2009</option><option value="2008">2008</option><option value="2007">2007</option><option value="2006">2006</option><option value="2005">2005</option><option value="2004">2004</option><option value="2003">2003</option><option value="2002">2002</option><option value="2001">2001</option><option value="2000">2000</option><option value="1999">1999</option><option value="1998">1998</option><option value="1997">1997</option><option value="1996">1996</option><option value="1995">1995</option><option value="1994">1994</option><option value="1993">1993</option><option value="1992">1992</option><option value="1991">1991</option><option value="1990">1990</option><option value="1989">1989</option><option value="1988">1988</option><option value="1987">1987</option><option value="1986">1986</option><option value="1985">1985</option><option value="1984">1984</option><option value="1983">1983</option><option value="1982">1982</option><option value="1981">1981</option><option value="1980">1980</option><option value="1979">1979</option><option value="1978">1978</option><option value="1977">1977</option><option value="1976">1976</option><option value="1975">1975</option><option value="1974">1974</option><option value="1973">1973</option><option value="1972">1972</option><option value="1971">1971</option><option value="1970">1970</option><option value="1969">1969</option><option value="1968">1968</option><option value="1967">1967</option><option value="1966">1966</option><option value="1965">1965</option><option value="1964">1964</option><option value="1963">1963</option><option value="1962">1962</option><option value="1961">1961</option><option value="1960">1960</option><option value="1959">1959</option><option value="1958">1958</option><option value="1957">1957</option><option value="1956">1956</option><option value="1955">1955</option><option value="1954">1954</option><option value="1953">1953</option><option value="1952">1952</option><option value="1951">1951</option><option value="1950">1950</option><option value="1949">1949</option><option value="1948">1948</option><option value="1947">1947</option><option value="1946">1946</option><option value="1945">1945</option><option value="1944">1944</option><option value="1943">1943</option><option value="1942">1942</option><option value="1941">1941</option><option value="1940">1940</option><option value="1939">1939</option><option value="1938">1938</option><option value="1937">1937</option><option value="1936">1936</option><option value="1935">1935</option><option value="1934">1934</option><option value="1933">1933</option><option value="1932">1932</option><option value="1931">1931</option><option value="1930">1930</option><option value="1929">1929</option><option value="1928">1928</option><option value="1927">1927</option></select>
      </div>
      <div class="ea-agegate__actions">
        <button type="submit" class="ea-agegate__btn ea-agegate__btn--primary">Enter site</button>
      </div>
    </form>
      <p class="ea-agegate__error" data-error hidden>Sorry, you don't meet the minimum age to enter.</p>
    </div>
  </div>
  <script>
  (function () {
    var el = document.getElementById('ea-age-gate');
    if (!el) return;
    function getCookie(name) {
      return document.cookie.split('; ').reduce(function (r, c) { var p = c.split('='); return p[0] === name ? decodeURIComponent(p[1]) : r; }, null);
    }
    function setCookie(name, value, days) {
      document.cookie = name + '=' + value + '; max-age=' + days * 86400 + '; path=/; samesite=lax';
    }
    if (getCookie('ea-age-verified') === '1') return;
    el.hidden = false;
    document.documentElement.style.overflow = 'hidden';
    function confirmOk() {
      setCookie('ea-age-verified', '1', Number(el.dataset.cookieDays) || 30);
      el.hidden = true;
      document.documentElement.style.overflow = '';
    }
    function decline() {
      if (el.dataset.decline === 'redirect' && el.dataset.redirect) { window.location.href = el.dataset.redirect; return; }
      var err = el.querySelector('[data-error]');
      if (err) err.hidden = false;
    }
    if (el.dataset.mode === 'yesno') {
      var yes = el.querySelector('[data-yes]');
      if (yes) yes.onclick = confirmOk;
      var no = el.querySelector('[data-no]');
      if (no) no.onclick = decline;
    } else {
      var form = el.querySelector('form');
      if (form) form.onsubmit = function (e) {
        e.preventDefault();
        var d = Number(el.querySelector('[name=ea-day]').value);
        var m = Number(el.querySelector('[name=ea-month]').value);
        var y = Number(el.querySelector('[name=ea-year]').value);
        if (!d || !m || !y) return;
        var dob = new Date(Date.UTC(y, m - 1, d));
        var today = new Date();
        var age = today.getUTCFullYear() - dob.getUTCFullYear() - (today.getUTCMonth() < m - 1 || (today.getUTCMonth() === m - 1 && today.getUTCDate() < d) ? 1 : 0);
        if (age >= (Number(el.dataset.minAge) || 18)) confirmOk(); else decline();
      };
    }
  })();
  </script>
{%- endif -%}

To install: in Shopify admin go to Online Store → Themes, click … next to your theme → Edit code. Under Snippets choose Add a new snippet, name it as shown above, paste this code and save. Add {% render 'age-verification' %} right after the opening <body> tag in theme.liquid, so it appears before the page's content.

This is a client-side, good-faith gate. It doesn't verify a real identity or birth date. Check whether your market requires a stricter, ID-based check for this product.

Live preview

Cookie-based, scoped to what needs it

The popup blocks the page (scroll and interaction) until the shopper confirms their age, either by typing a date of birth or answering yes/no, whichever you choose. Once confirmed, it's remembered in a cookie for the number of days you set, so returning visitors within that window aren't asked again.

Set it to show storewide, or only when the shopper is on a specific collection or viewing a product with a specific tag, so you're not gating an entire store over one age-restricted category.

Adding it to your theme

  1. 01

    Add the snippet

    Online Store → Themes → Edit code → Snippets → Add a new snippet named age-verification, paste the code.

  2. 02

    Include it early

    Add {% render 'age-verification' %} right after the opening <body> tag in theme.liquid, so it appears before the page's content to avoid a flash of the page underneath.

This is a client-side gate: it improves compliance and shows good faith, but it doesn't verify a real identity or birth date. If you sell a product with strict legal age-verification requirements in your market, check whether your jurisdiction requires a more rigorous, ID-based check.

Questions people ask

Can a shopper get around this by clearing cookies?

Yes, and by disabling JavaScript. As noted above, this is a good-faith, client-side gate, not a hard security control.

Does the date-of-birth mode store the birth date anywhere?

No, it only stores a yes/no "verified" flag in the cookie once the entered date clears your minimum age; the date itself isn't saved or sent anywhere.

What happens if they say they're under the minimum age?

Whatever you set as the decline action: either they're redirected to a page you choose (for example a general age-appropriate page) or the popup simply stays up.

Will this slow down my page?

It's a small snippet with no external requests, so the impact is minimal; the main cost is the same as any content shown immediately on load.

Want this builtinto your store?

I'm Emmanuel, a Shopify and WooCommerce developer. If this tool pointed at something you'd rather have fixed for you (a faster store, cleaner product data, a migration, a custom feature), send me a note.

Emmanuel Asika

Emmanuel Asika

Shopify & WooCommerce developer, Dublin

I build and fix online stores: new builds, migrations, speed, SEO and the custom bits apps can't do.

hello@emmanuelasika.com

Last reviewed 30 September 2026.