<?php
// tools/whatsapp-qr-code-generator.php — Free WhatsApp QR Code Generator
$root = rtrim($_SERVER['DOCUMENT_ROOT'], '/');
$pageTitle = 'WhatsApp QR Code Generator — Free Click-to-Chat QR Maker';
include $root . '/includes/header.php';
?>

<link rel="canonical" href="https://fidusflo.com/tools/whatsapp-qr-code-generator">

<style>
.qr-wrap { max-width: 1060px; margin: 0 auto; padding: 0 20px 90px; }

/* Hero */
.qr-hero { padding: 54px 0 30px; }
.qr-hero .kicker { font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--accent); margin-bottom: 12px; }
.qr-hero h1 { font-family: 'Syne', sans-serif; font-size: clamp(26px, 4.4vw, 40px); font-weight: 800; color: var(--text); margin: 0 0 14px; line-height: 1.14; }
.qr-hero p { font-size: 16px; color: var(--muted); line-height: 1.7; max-width: 640px; }

/* Tool layout */
.qr-tool { display: grid; grid-template-columns: 1fr 340px; gap: 28px; align-items: start; background: var(--bg); border: 1px solid var(--border, rgba(0,0,0,.08)); border-radius: 18px; padding: 28px; }
@media(max-width: 760px){ .qr-tool { grid-template-columns: 1fr; } }

.qr-field { margin-bottom: 20px; }
.qr-field label { display: block; font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.qr-field .hint { font-size: 12px; color: var(--muted); margin-top: 6px; }
.qr-phone { display: flex; gap: 8px; }
.qr-phone select { flex: 0 0 96px; }
.qr-tool input[type=text], .qr-tool input[type=tel], .qr-tool textarea, .qr-tool select {
  width: 100%; background: var(--bg2, rgba(0,0,0,.02)); border: 1px solid var(--border, rgba(0,0,0,.12)); border-radius: 10px;
  padding: 11px 13px; font-size: 15px; color: var(--text); font-family: inherit; outline: none; }
.qr-tool input:focus, .qr-tool textarea:focus, .qr-tool select:focus { border-color: var(--accent); }
.qr-tool textarea { resize: vertical; min-height: 70px; line-height: 1.5; }

/* Colour swatches */
.qr-swatches { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.qr-sw { width: 30px; height: 30px; border-radius: 8px; border: 2px solid transparent; cursor: pointer; box-shadow: 0 0 0 1px var(--border, rgba(0,0,0,.12)) inset; }
.qr-sw.active { border-color: var(--accent); }
.qr-sw-custom { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.qr-sw-custom input[type=color] { width: 30px; height: 30px; padding: 0; border: 1px solid var(--border, rgba(0,0,0,.12)); border-radius: 8px; background: none; cursor: pointer; }

/* Preview column */
.qr-preview { position: sticky; top: 20px; text-align: center; }
.qr-canvas-box { background: #fff; border: 1px solid var(--border, rgba(0,0,0,.10)); border-radius: 14px; padding: 18px; display: inline-flex; align-items: center; justify-content: center; min-height: 296px; min-width: 296px; }
#qr-canvas { display: block; }
.qr-empty { color: #9aa3b2; font-size: 13.5px; max-width: 200px; line-height: 1.5; }
.qr-link { margin-top: 16px; display: flex; gap: 8px; }
.qr-link input { font-size: 13px !important; color: var(--muted) !important; }
.qr-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; border: 0; border-radius: 10px; font-size: 13.5px; font-weight: 700; cursor: pointer; padding: 10px 14px; text-decoration: none; }
.qr-btn.primary { background: var(--accent); color: #fff; }
.qr-btn.ghost { background: var(--bg2, rgba(0,0,0,.04)); color: var(--text); border: 1px solid var(--border, rgba(0,0,0,.12)); }
.qr-btn:disabled { opacity: .45; cursor: not-allowed; }
.qr-downloads { margin-top: 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.qr-priv { margin-top: 14px; font-size: 11.5px; color: var(--muted); display: flex; align-items: center; gap: 6px; justify-content: center; }
.qr-err { color: #dc2626; font-size: 12.5px; margin-top: 8px; min-height: 16px; }

/* SEO content */
.qr-content { max-width: 760px; margin: 56px auto 0; }
.qr-content h2 { font-family: 'Syne', sans-serif; font-size: 24px; font-weight: 800; color: var(--text); margin: 40px 0 14px; }
.qr-content h3 { font-size: 17px; font-weight: 700; color: var(--text); margin: 26px 0 8px; }
.qr-content p { font-size: 16px; line-height: 1.8; color: var(--text); margin: 0 0 16px; }
.qr-content ul { margin: 0 0 18px; padding-left: 22px; }
.qr-content li { margin-bottom: 8px; line-height: 1.7; color: var(--text); }
.qr-content a { color: var(--accent); text-decoration: underline; }
.qr-steps { counter-reset: s; list-style: none; padding: 0; }
.qr-steps li { counter-increment: s; position: relative; padding-left: 42px; margin-bottom: 16px; }
.qr-steps li::before { content: counter(s); position: absolute; left: 0; top: 0; width: 28px; height: 28px; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 800; font-size: 14px; display: flex; align-items: center; justify-content: center; }
.qr-faq { margin-top: 10px; }
.qr-faq details { border-bottom: 1px solid var(--border, rgba(0,0,0,.08)); padding: 14px 0; }
.qr-faq summary { font-weight: 700; color: var(--text); cursor: pointer; font-size: 15.5px; list-style: none; }
.qr-faq summary::-webkit-details-marker { display: none; }
.qr-faq summary::after { content: '+'; float: right; color: var(--accent); font-weight: 700; }
.qr-faq details[open] summary::after { content: '–'; }
.qr-faq p { margin: 12px 0 0; font-size: 15px; color: var(--muted); }

.qr-cta { margin: 48px auto 0; max-width: 760px; padding: 28px 30px; border-radius: 14px; background: linear-gradient(135deg, #1B3A6B 0%, #2E75B6 100%); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 14px; }
.qr-cta p { margin: 0; color: rgba(255,255,255,.92); font-size: 15px; font-weight: 600; }
.qr-cta a { background: #fff; color: #1B3A6B; padding: 10px 22px; border-radius: 8px; font-weight: 700; font-size: 14px; text-decoration: none; white-space: nowrap; }
.qr-sib { margin-top: 26px; font-size: 14px; color: var(--muted); }
.qr-sib a { color: var(--accent); text-decoration: none; font-weight: 600; }
</style>

<main>
<div class="qr-wrap">

  <header class="qr-hero">
    <div class="kicker">FREE TOOL</div>
    <h1>WhatsApp QR Code Generator</h1>
    <p>Turn your WhatsApp number into a free, scannable QR code. Add a pre-filled message, pick a colour, and download a print-ready PNG or SVG — no signup, generated right in your browser.</p>
  </header>

  <!-- ── TOOL ── -->
  <div class="qr-tool">

    <!-- Controls -->
    <div class="qr-controls">
      <div class="qr-field">
        <label for="qr-number">WhatsApp number</label>
        <div class="qr-phone">
          <select id="qr-cc" aria-label="Country code">
            <option value="91" selected>🇮🇳 +91</option>
            <option value="1">🇺🇸 +1</option>
            <option value="44">🇬🇧 +44</option>
            <option value="971">🇦🇪 +971</option>
            <option value="65">🇸🇬 +65</option>
            <option value="61">🇦🇺 +61</option>
            <option value="60">🇲🇾 +60</option>
            <option value="92">🇵🇰 +92</option>
            <option value="880">🇧🇩 +880</option>
            <option value="977">🇳🇵 +977</option>
            <option value="94">🇱🇰 +94</option>
            <option value="49">🇩🇪 +49</option>
            <option value="33">🇫🇷 +33</option>
            <option value="55">🇧🇷 +55</option>
            <option value="27">🇿🇦 +27</option>
          </select>
          <input type="tel" id="qr-number" inputmode="numeric" placeholder="98765 43210" autocomplete="off">
        </div>
        <div class="hint">Enter the number without the country code or leading zero.</div>
      </div>

      <div class="qr-field">
        <label for="qr-msg">Pre-filled message <span style="font-weight:400;text-transform:none;letter-spacing:0;">(optional)</span></label>
        <textarea id="qr-msg" maxlength="600" placeholder="Hi! I saw your WhatsApp QR code and I'd like to know more."></textarea>
        <div class="hint">This text appears in the chat box when someone scans the code.</div>
      </div>

      <div class="qr-field">
        <label>QR colour</label>
        <div class="qr-swatches">
          <span class="qr-sw active" data-color="#111111" style="background:#111111" title="Black"></span>
          <span class="qr-sw" data-color="#1B3A6B" style="background:#1B3A6B" title="FLO Navy"></span>
          <span class="qr-sw" data-color="#2E75B6" style="background:#2E75B6" title="FLO Blue"></span>
          <span class="qr-sw" data-color="#128C4B" style="background:#128C4B" title="Green"></span>
          <label class="qr-sw-custom">
            <input type="color" id="qr-color" value="#111111"> Custom
          </label>
        </div>
        <div class="hint">Dark colours on white scan best. Keep contrast high.</div>
      </div>

      <div class="qr-field">
        <label for="qr-size">Download size</label>
        <select id="qr-size">
          <option value="512">512 px — web / social</option>
          <option value="1024" selected>1024 px — flyers / standees</option>
          <option value="2048">2048 px — large print</option>
        </select>
      </div>
    </div>

    <!-- Preview -->
    <div class="qr-preview">
      <div class="qr-canvas-box">
        <canvas id="qr-canvas" width="260" height="260" style="display:none;"></canvas>
        <div class="qr-empty" id="qr-empty">Your QR code will appear here as you type a number.</div>
      </div>
      <div class="qr-err" id="qr-err"></div>

      <div class="qr-link">
        <input type="text" id="qr-url" readonly placeholder="wa.me link appears here">
        <button class="qr-btn ghost" id="qr-copy" type="button" disabled>Copy</button>
      </div>

      <div class="qr-downloads">
        <button class="qr-btn primary" id="qr-png" type="button" disabled>Download PNG</button>
        <button class="qr-btn ghost" id="qr-svg" type="button" disabled>Download SVG</button>
      </div>

      <div class="qr-priv">🔒 Generated in your browser — nothing is sent to a server.</div>
    </div>

  </div>

  <!-- ── SEO CONTENT ── -->
  <div class="qr-content">

    <h2>What is a WhatsApp QR code?</h2>
    <p>A WhatsApp QR code is a scannable image that opens a chat with your business the moment a customer points their phone camera at it — no saving your number, no typing. Under the hood it encodes a <strong>click-to-chat link</strong> (a <code>wa.me</code> URL), and you can pre-load the first message so the conversation starts on your terms. It is the fastest way to turn a physical touchpoint — a shop counter, a flyer, a delivery box — into a WhatsApp lead.</p>

    <h2>How to create a WhatsApp QR code</h2>
    <ol class="qr-steps">
      <li><strong>Enter your WhatsApp number</strong> with the correct country code (the tool above defaults to India, +91).</li>
      <li><strong>Add a pre-filled message</strong> (optional) so customers don't have to think about what to say — &ldquo;Hi, I'd like to book an appointment&rdquo; works well.</li>
      <li><strong>Pick a colour and size</strong>, then download your QR code as a PNG for screens or an SVG for crisp, large-format printing.</li>
      <li><strong>Place it where your customers are</strong> — print it, add it to designs, or drop it into your ads.</li>
    </ol>

    <h2>Where to use your WhatsApp QR code</h2>
    <ul>
      <li><strong>Shopfront &amp; counter</strong> — let walk-ins start a chat for offers, bookings or support.</li>
      <li><strong>Product packaging &amp; delivery boxes</strong> — turn every order into a re-engagement channel.</li>
      <li><strong>Flyers, posters &amp; standees</strong> — a scannable call-to-action beats a phone number nobody types.</li>
      <li><strong>Business cards &amp; email signatures</strong> — open a chat in one tap.</li>
      <li><strong>Instagram, Facebook &amp; Google ads</strong> — pair it with a click-to-WhatsApp campaign.</li>
    </ul>

    <h2>Frequently asked questions</h2>
    <div class="qr-faq">
      <details><summary>Is this WhatsApp QR code generator free?</summary><p>Yes — completely free, with no signup and no watermark. You can generate and download as many codes as you like.</p></details>
      <details><summary>Does the QR code expire?</summary><p>No. The code points to your WhatsApp number, so it works for as long as that number is active on WhatsApp. Print it once and reuse it forever.</p></details>
      <details><summary>Can I add a pre-filled message?</summary><p>Yes. Whatever you type in the message field is loaded into the chat box when someone scans the code — they just hit send.</p></details>
      <details><summary>Do I need WhatsApp Business?</summary><p>No — it works with any WhatsApp number. If you run a business, WhatsApp Business (or the Business API via <a href="/flo-konnect.php">FLO Konnect</a>) gives you a verified profile, automated replies and a team inbox.</p></details>
      <details><summary>Is my number stored anywhere?</summary><p>No. The QR code is generated entirely in your browser — your number and message never leave your device.</p></details>
      <details><summary>Can I print it large without it going blurry?</summary><p>Yes. Download the <strong>SVG</strong> for infinitely scalable print, or the 2048&nbsp;px PNG for big standees and banners.</p></details>
    </div>

  </div>

  <div class="qr-cta">
    <p>Getting scans is step one. FLO Konnect handles the conversations and follow-up that turn them into customers.</p>
    <a href="/flo-konnect.php">Explore FLO Konnect →</a>
  </div>

  <p class="qr-sib" style="max-width:760px;margin-left:auto;margin-right:auto;">
    More free tools: <a href="/tools/whatsapp-link-generator">WhatsApp Link Generator</a> · <a href="/tools/whatsapp-text-formatter">WhatsApp Text Formatter</a> · <a href="/tools/upi-qr-code-generator">UPI QR Code Generator</a> · <a href="/tools/">all tools →</a>
  </p>

</div>
</main>

<script src="/assets/vendor/qrcode.min.js?v=1"></script>
<script>
(function () {
  var ccEl = document.getElementById('qr-cc');
  var numEl = document.getElementById('qr-number');
  var msgEl = document.getElementById('qr-msg');
  var colorEl = document.getElementById('qr-color');
  var sizeEl = document.getElementById('qr-size');
  var canvas = document.getElementById('qr-canvas');
  var emptyEl = document.getElementById('qr-empty');
  var urlEl = document.getElementById('qr-url');
  var errEl = document.getElementById('qr-err');
  var copyBtn = document.getElementById('qr-copy');
  var pngBtn = document.getElementById('qr-png');
  var svgBtn = document.getElementById('qr-svg');
  var swatches = document.querySelectorAll('.qr-sw');

  var state = { color: '#111111', url: '' };

  // Guard: if the QR library didn't load, fail loudly instead of a blank canvas
  if (typeof QRCode === 'undefined' || !QRCode.toCanvas) {
    if (emptyEl) {
      emptyEl.textContent = 'QR engine failed to load. Please hard-refresh — if it persists, confirm /assets/vendor/qrcode.min.js is uploaded.';
      emptyEl.style.color = '#dc2626';
    }
    return;
  }

  swatches.forEach(function (sw) {
    sw.addEventListener('click', function () {
      swatches.forEach(function (s) { s.classList.remove('active'); });
      sw.classList.add('active');
      state.color = sw.getAttribute('data-color');
      colorEl.value = state.color;
      render();
    });
  });
  colorEl.addEventListener('input', function () {
    state.color = colorEl.value;
    swatches.forEach(function (s) { s.classList.remove('active'); });
    render();
  });

  function buildUrl() {
    var cc = (ccEl.value || '').replace(/\D/g, '');
    var num = (numEl.value || '').replace(/\D/g, '');
    if (!num) return { empty: true };
    var full = cc + num;
    if (full.length < 8 || full.length > 15) return { error: 'Enter a valid number with its country code.' };
    var url = 'https://wa.me/' + full;
    var msg = (msgEl.value || '').trim();
    if (msg) url += '?text=' + encodeURIComponent(msg);
    return { url: url };
  }

  function setEnabled(on) {
    copyBtn.disabled = !on; pngBtn.disabled = !on; svgBtn.disabled = !on;
  }

  function render() {
    var res = buildUrl();
    if (res.empty) {
      canvas.style.display = 'none'; emptyEl.style.display = 'block';
      urlEl.value = ''; errEl.textContent = ''; state.url = ''; setEnabled(false);
      return;
    }
    if (res.error) {
      canvas.style.display = 'none'; emptyEl.style.display = 'block';
      urlEl.value = ''; errEl.textContent = res.error; state.url = ''; setEnabled(false);
      return;
    }
    errEl.textContent = '';
    state.url = res.url;
    urlEl.value = res.url;
    QRCode.toCanvas(canvas, res.url, {
      width: 260, margin: 2, errorCorrectionLevel: 'M',
      color: { dark: state.color, light: '#ffffff' }
    }, function (err) {
      if (err) { errEl.textContent = 'Could not render QR code.'; return; }
      canvas.style.display = 'block'; emptyEl.style.display = 'none'; setEnabled(true);
    });
  }

  function debounce(fn, ms) { var t; return function () { clearTimeout(t); t = setTimeout(fn, ms); }; }
  var deb = debounce(render, 180);
  [ccEl, numEl, msgEl, sizeEl].forEach(function (el) {
    el.addEventListener('input', deb); el.addEventListener('change', deb);
  });

  function triggerDownload(href, name) {
    var a = document.createElement('a');
    a.href = href; a.download = name;
    document.body.appendChild(a); a.click(); document.body.removeChild(a);
  }

  pngBtn.addEventListener('click', function () {
    if (!state.url) return;
    var size = parseInt(sizeEl.value, 10) || 1024;
    QRCode.toDataURL(state.url, {
      width: size, margin: 2, errorCorrectionLevel: 'M',
      color: { dark: state.color, light: '#ffffff' }
    }, function (err, dataUrl) {
      if (err) { errEl.textContent = 'PNG export failed.'; return; }
      triggerDownload(dataUrl, 'whatsapp-qr-code.png');
    });
  });

  svgBtn.addEventListener('click', function () {
    if (!state.url) return;
    var size = parseInt(sizeEl.value, 10) || 1024;
    QRCode.toString(state.url, {
      type: 'svg', width: size, margin: 2, errorCorrectionLevel: 'M',
      color: { dark: state.color, light: '#ffffff' }
    }, function (err, svg) {
      if (err) { errEl.textContent = 'SVG export failed.'; return; }
      var blob = new Blob([svg], { type: 'image/svg+xml' });
      var url = URL.createObjectURL(blob);
      triggerDownload(url, 'whatsapp-qr-code.svg');
      setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
    });
  });

  copyBtn.addEventListener('click', function () {
    if (!state.url) return;
    navigator.clipboard.writeText(state.url).then(function () {
      var old = copyBtn.textContent; copyBtn.textContent = 'Copied ✓';
      setTimeout(function () { copyBtn.textContent = old; }, 1500);
    });
  });
})();
</script>

<!-- Schema -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  "name": "WhatsApp QR Code Generator",
  "applicationCategory": "BusinessApplication",
  "operatingSystem": "Web",
  "url": "https://fidusflo.com/tools/whatsapp-qr-code-generator",
  "description": "Free tool to turn a WhatsApp number into a scannable QR code with a pre-filled message. Download print-ready PNG or SVG. No signup.",
  "offers": { "@type": "Offer", "price": "0", "priceCurrency": "INR" },
  "provider": { "@type": "Organization", "name": "FIDUS FLO", "url": "https://fidusflo.com" }
}
</script>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "HowTo",
  "name": "How to create a WhatsApp QR code",
  "step": [
    { "@type": "HowToStep", "position": 1, "name": "Enter your WhatsApp number", "text": "Enter your WhatsApp number with the correct country code." },
    { "@type": "HowToStep", "position": 2, "name": "Add a pre-filled message", "text": "Optionally add a message that loads into the chat when scanned." },
    { "@type": "HowToStep", "position": 3, "name": "Customise and download", "text": "Pick a colour and size, then download as PNG or SVG." },
    { "@type": "HowToStep", "position": 4, "name": "Place it", "text": "Print or add the QR code wherever your customers are." }
  ]
}
</script>
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    { "@type": "Question", "name": "Is this WhatsApp QR code generator free?", "acceptedAnswer": { "@type": "Answer", "text": "Yes, completely free with no signup and no watermark. Generate and download as many codes as you like." } },
    { "@type": "Question", "name": "Does the WhatsApp QR code expire?", "acceptedAnswer": { "@type": "Answer", "text": "No. It points to your WhatsApp number and works as long as that number is active. Print it once and reuse it." } },
    { "@type": "Question", "name": "Can I add a pre-filled message to the QR code?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. Whatever you type in the message field loads into the chat box when someone scans the code." } },
    { "@type": "Question", "name": "Do I need WhatsApp Business to use a QR code?", "acceptedAnswer": { "@type": "Answer", "text": "No, it works with any WhatsApp number. For businesses, WhatsApp Business or the Business API via FLO Konnect adds a verified profile, automated replies and a team inbox." } },
    { "@type": "Question", "name": "Is my number stored anywhere?", "acceptedAnswer": { "@type": "Answer", "text": "No. The QR code is generated entirely in your browser; your number and message never leave your device." } }
  ]
}
</script>

<?php include $root . '/includes/footer.php'; ?>
