<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Pie · Ship the feature. Not the bug.</title><meta name="description" content="Pie tests every change like a real user, catches what breaks, and opens the fix before it ever reaches your users."><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="preconnect" href="https://api.fontshare.com"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://api.fontshare.com/v2/css?f[]=cabinet-grotesk@500,700,800&f[]=switzer@400,500,600,700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Martian+Mono:wght@400;500;600&display=swap" rel="stylesheet"><link rel="stylesheet" href="/redesign/styles.css"><link rel="stylesheet" href="/_astro/_slug_.JIDIUIfv.css"></head> <body> <script>
/* 3D intro gate: homepage only, once per session, motion-ok, desktop, WebGL-ok.
   Runs pre-paint so the intro-created elements (rings, card, nav logo) never flash. */
(function(){try{
  if(location.pathname!=='/')return;
  /* #intro forces a replay (testing/demo); #introslow plays it at 1/3 speed */
  addEventListener('hashchange',function(){if(location.hash.indexOf('#intro')===0)location.reload();});
  var force=location.hash.indexOf('#intro')===0;
  if(!force){
    if(sessionStorage.getItem('pieIntro'))return;
    if(matchMedia('(prefers-reduced-motion: reduce)').matches)return;
  }
  var c=document.createElement('canvas');
  if(!(c.getContext('webgl2')||c.getContext('webgl')))return;
  if(!force)sessionStorage.setItem('pieIntro','1');
  document.documentElement.setAttribute('data-intro','');
  /* failsafe: if the scene isn't live fast (slow cellular, module/webgl failure),
     reveal the page and skip the show. Better a normal hero than a blank one. */
  setTimeout(function(){var h=document.documentElement;
    if(h.hasAttribute('data-intro')&&!h.classList.contains('intro-live')&&!h.classList.contains('intro-done')){
      h.classList.add('intro-card','intro-rings','intro-nav','intro-done');
      h.removeAttribute('data-intro');
      try{dispatchEvent(new Event('pie:card'))}catch(e){}
    }},3200);
}catch(e){}})();
</script> <nav> <div class="nl"><div class="nvi"><a href="/product/how-it-works/">Product</a> <div class="dd"><div class="ddc"> <a href="/product/pie-qa/"><b>Pie QA</b><span>The platform at a glance</span></a> <a href="/product/overview/"><b>Product Overview</b><span>Vision-first testing</span></a> <a href="/product/how-it-works/"><b>How Pie Works</b><span>Push. Probe. Pass.</span></a> <a href="/product/autonomous-discovery/"><b>Autonomous Discovery</b><span>Coverage from a URL</span></a> <a href="/product/self-healing-tests/"><b>Self-Healing Tests</b><span>Tests that survive redesigns</span></a> <a href="/product/integrations/"><b>Integrations</b><span>GitHub, Slack, Jira, MCP</span></a> <a href="/product/custom-tests/"><b>Custom Tests</b><span>Plain-English test authoring</span></a> <a href="/product/security/"><b>Security</b><span>SOC 2 Type 2, scoped access</span></a> </div></div></div> <a href="https://docs.pie.inc/" target="_blank">Docs</a> <div class="nvi"><a href="/blog/">Resources</a> <div class="dd"><div class="ddc"> <a href="/blog/"><b>Blog</b><span>Guides and engineering notes</span></a> <a href="/customers/"><b>Case studies</b><span>Fi, Tilt, and more</span></a> <a href="/resources/whitepapers/"><b>Whitepapers</b><span>The long answers</span></a> </div></div></div> </div> <a class="logo" href="/" aria-label="Pie home"><img class="lg-b" src="/redesign/pie-badge.svg" alt="" style="height:28px;display:block"><span class="lg-w"><img src="/redesign/pie-word.svg" alt="pie" style="height:28px;display:block"></span></a> <div class="rt"><a href="https://app.pie.inc/">Log in</a><a class="btn p" href="https://calendly.com/jinoo-pie/demo">Book a demo</a></div> <button class="burger" id="burger" aria-label="Open menu" aria-expanded="false" aria-controls="mnav"><span></span><span></span><span></span></button> <div class="mnav" id="mnav"> <div class="mn-group"><b>Product</b><div class="mn-cols"> <a href="/product/pie-qa/">Pie QA</a> <a href="/product/overview/">Product Overview</a> <a href="/product/how-it-works/">How Pie Works</a> <a href="/product/autonomous-discovery/">Autonomous Discovery</a> <a href="/product/self-healing-tests/">Self-Healing Tests</a> <a href="/product/integrations/">Integrations</a> <a href="/product/custom-tests/">Custom Tests</a> <a href="/product/security/">Security</a> </div></div> <div class="mn-group"><b>Resources</b><div class="mn-cols"> <a href="https://docs.pie.inc/" target="_blank">Docs</a> <a href="/blog/">Blog</a> <a href="/customers/">Case studies</a> <a href="/resources/whitepapers/">Whitepapers</a> </div></div> <div class="mn-actions"><a href="https://app.pie.inc/">Log in</a><a class="btn p" href="https://calendly.com/jinoo-pie/demo">Book a demo</a></div> </div> </nav>  <!-- 3D intro, round 6: trace -> ink -> mint -> slow show-off spin (tilt sweep) ->
     stamp (ring #1 on impact) -> a badge-shaped PORTAL opens at the stamp point,
     the chip sinks through the page (real clip plane), the portal seals -> a twin
     portal opens at the nav and the chip rises out, settling as the DOM logo.
     Finish/edge/speed via hash: #introchrome (default) #introsatin #introenamel ·
     #introchamfer (default) #introrazor #introfillet #intropillow · #introslowN.
     Gated by the inline script in RedesignLayout (html[data-intro]). --><script type="module" src="/_astro/Intro.astro_astro_type_script_index_0_lang.BQIbip9t.js"></script> <!-- HERO (ripple #1, subtle) --><section class="hero"> <svg class="rip"></svg> <div class="wrap"><div class="grid"> <div> <div class="eyebrow">Agentic testing · <span style="text-transform:none">iOS</span> &amp; Android &amp; Web</div> <h1>Ship the feature.<br><span class="hl">Not the bug.</span></h1> <p class="sub">Pie tests every change like a real user, catches what breaks, and opens the fix before it ever reaches your users.</p> <div class="cta"><a class="btn p" href="https://app.pie.inc/start">See what Pie finds in your app <span class="ar">→</span></a><a class="btn g" href="https://calendly.com/jinoo-pie/demo">Book a demo</a></div> </div> <!-- 3-scene run: read PR → test app → ship fix (ported from the live hero, rethemed) --> <div class="artifact hd-shell"> <div class="hd-wrap" id="hd-wrap"> <!-- Step pill timeline --> <div class="hd-timeline" aria-hidden="true"> <div class="hd-pill" data-pill="1"> <span class="hd-pill-ring"><span class="hd-pill-ring-inner">1</span></span> <span class="hd-pill-label">Read PR</span> </div> <div class="hd-conn" data-conn="1"><span class="hd-conn-fill"></span></div> <div class="hd-pill" data-pill="2"> <span class="hd-pill-ring"><span class="hd-pill-ring-inner">2</span></span> <span class="hd-pill-label">Test app</span> </div> <div class="hd-conn" data-conn="2"><span class="hd-conn-fill"></span></div> <div class="hd-pill" data-pill="3"> <span class="hd-pill-ring"><span class="hd-pill-ring-inner">3</span></span> <span class="hd-pill-label">Ship fix</span> </div> </div> <!-- Stage --> <div class="hd-stage"> <!-- SCENE 1 — code diff --> <div class="hd-scene hd-scene--active" data-scene="1"> <div class="hd-scene-inner hd-scene-1"> <div class="hd-s1-col"> <div class="hd-scene-head"> <div class="hd-eyebrow">PULL REQUEST</div> <div class="hd-title">feat: proceed-to-cart button</div> </div> <div class="hd-editor"> <div class="hd-editor-chrome"> <div class="hd-dots"><span></span><span></span><span></span></div> <div class="hd-editor-tab"> <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"> <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> </svg> <span>CheckoutButton.tsx</span> </div> <div class="hd-editor-status" id="hd-s1-status">scanning · 0%</div> </div> <div class="hd-code" id="hd-code"> <div class="hd-code-track" id="hd-code-track"> <div class="hd-code-line"><span class="hd-code-ln">1</span><span class="hd-code-tx">import { useState } from &#39;react&#39;;</span></div> <div class="hd-code-line"><span class="hd-code-ln">2</span><span class="hd-code-tx">import { Button } from &#39;./ui&#39;;</span></div> <div class="hd-code-line hd-code-line--add"><span class="hd-code-ln">3</span><span class="hd-code-tx"><span class="hd-code-plus">+</span>import { useCart } from &#39;./cart&#39;;</span></div> <div class="hd-code-line hd-code-line--blank"><span class="hd-code-ln">4</span><span class="hd-code-tx"></span></div> <div class="hd-code-line"><span class="hd-code-ln">5</span><span class="hd-code-tx">interface Props { product: Product }</span></div> <div class="hd-code-line hd-code-line--blank"><span class="hd-code-ln">6</span><span class="hd-code-tx"></span></div> <div class="hd-code-line"><span class="hd-code-ln">7</span><span class="hd-code-tx">export function CheckoutButton({ product }: Props) {</span></div> <div class="hd-code-line"><span class="hd-code-ln">8</span><span class="hd-code-tx"> const { addItem } = useCart();</span></div> <div class="hd-code-line"><span class="hd-code-ln">9</span><span class="hd-code-tx"> const [loading, setLoading] = useState(false);</span></div> <div class="hd-code-line hd-code-line--blank"><span class="hd-code-ln">10</span><span class="hd-code-tx"></span></div> <div class="hd-code-line"><span class="hd-code-ln">11</span><span class="hd-code-tx"> const handleClick = async () =&gt; {</span></div> <div class="hd-code-line"><span class="hd-code-ln">12</span><span class="hd-code-tx"> setLoading(true);</span></div> <div class="hd-code-line"><span class="hd-code-ln">13</span><span class="hd-code-tx"> await addItem(product);</span></div> <div class="hd-code-line"><span class="hd-code-ln">14</span><span class="hd-code-tx"> };</span></div> <div class="hd-code-line hd-code-line--blank"><span class="hd-code-ln">15</span><span class="hd-code-tx"></span></div> <div class="hd-code-line hd-code-crit"><span class="hd-code-ln">16</span><span class="hd-code-tx"> return &lt;Button onClick={handleClick} disabled={<span class="hd-code-hl">loading</span>}&gt;Proceed to cart&lt;/Button&gt;;</span></div> <div class="hd-code-line"><span class="hd-code-ln">17</span><span class="hd-code-tx">}</span></div> </div> <div class="hd-code-scan" id="hd-code-scan"></div> <div class="hd-code-fade"></div> </div> </div> </div> </div> </div> <!-- SCENE 2 — browser Lottie --> <div class="hd-scene" data-scene="2"> <div class="hd-scene-inner hd-scene-2"> <div class="hd-s2-col"> <div class="hd-scene-head"> <div class="hd-eyebrow">LIVE TEST</div> <div class="hd-title">Walking through checkout like a user</div> </div> <div class="hd-browser"> <div class="hd-browser-chrome"> <div class="hd-dots"><span></span><span></span><span></span></div> <div class="hd-browser-url"> <svg width="9" height="9" viewBox="0 0 9 9" fill="none" stroke="currentColor" stroke-width="1.2"><rect x="2" y="4" width="5" height="4" rx="0.6"></rect><path d="M3 4V2.8a1.5 1.5 0 1 1 3 0V4"></path></svg> <span>staging.acme.com/checkout</span> </div> </div> <div class="hd-browser-body"> <div id="hd-lottie" class="hd-lottie" role="img" aria-label="Pie navigating a product page and detecting a broken proceed-to-cart button"></div> </div> </div> <div class="hd-s2-sub"> <span class="hd-s2-sub-dot"></span> <span>Proceed to cart button isn't clickable — users can't reach checkout</span> </div> </div> </div> </div> <!-- SCENE 3 — PR card --> <div class="hd-scene" data-scene="3"> <div class="hd-scene-inner hd-scene-3"> <div class="hd-s3-col"> <div class="hd-scene-head"> <div class="hd-eyebrow">FIX PR</div> <div class="hd-title">Pie drafted the fix</div> </div> <div class="hd-pr"> <div class="hd-pr-head" data-r="0.05"> <div class="hd-pr-avatar"> <svg viewBox="0 0 20 20" fill="none"><path d="M10 0C10.9147 0 11.7336.4047 12.292 1.043C12.5903 1.361 12.9455 1.622 13.3633 1.8C13.7976 1.984 14.2506 2.057 14.6924 2.036C15.5571 1.989 16.4238 2.281 17.0713 2.929C17.7177 3.575 18.0092 4.44 17.9531 5.285C17.9229 6.208 18.2865 7.088 18.9561 7.697C19.5967 8.271 20 9.088 20 10C20 10.912 19.5964 11.728 18.9609 12.286C18.2789 12.907 17.9109 13.796 17.9561 14.707C18.0098 15.559 17.7182 16.425 17.0713 17.071C16.4237 17.719 15.5571 18.011 14.71 17.953C14.2463 17.946 13.7949 18.019 13.3623 18.202C12.9468 18.379 12.5925 18.638 12.3066 18.951C11.7336 19.595 10.915 20 10 20C9.084 20 8.2644 19.594 7.706 18.954C7.405 18.638 7.0521 18.378 6.6377 18.202C6.2067 18.019 5.757 17.947 5.3184 17.966C4.4458 18.011 3.5781 17.72 2.9297 17.071C2.2808 16.423 1.9879 15.554 2.0469 14.705C2.0839 13.793 1.7199 12.911 1.0479 12.302C.4062 11.735 0 10.916 0 10C0 9.084.4059 8.264 1.0459 7.706C1.7122 7.084 2.0727 6.212 2.0342 5.316C1.9879 4.446 2.2798 3.578 2.9287 2.929C3.5773 2.28 4.4456 1.988 5.294 2.047C5.7521 2.056 6.2038 1.984 6.6367 1.8C7.0533 1.623 7.4072 1.362 7.6934 1.048C8.2644.405 9.0843 0 10 0Z" fill="#6B21A8"></path><path d="M9.83 5.017C10.517 5.017 11.145 5.182 11.711 5.514C12.285 5.837 12.734 6.287 13.057 6.86C13.38 7.426 13.541 8.058 13.541 8.753C13.541 9.446 13.39 10.081 13.085 10.654C12.789 11.219 12.375 11.665 11.844 11.989C11.32 12.314 10.733 12.477 10.088 12.477C9.568 12.477 9.081 12.368 8.63 12.151C8.3 11.993 8.006 11.788 7.749 11.538V14.635C7.749 14.865 7.677 15.066 7.524 15.219C7.371 15.372 7.171 15.443 6.94 15.443C6.716 15.443 6.52 15.37 6.361 15.222C6.204 15.066 6.133 14.865 6.133 14.635V8.753C6.133 8.058 6.294 7.426 6.617 6.859C6.948 6.286 7.392 5.838 7.948 5.515C8.514 5.182 9.143 5.017 9.83 5.017Z" fill="#EC4899"></path><path d="M10.23 4.617C10.917 4.617 11.545 4.782 12.111 5.114C12.685 5.437 13.134 5.887 13.457 6.46C13.78 7.026 13.941 7.658 13.941 8.353C13.941 9.046 13.79 9.681 13.485 10.254C13.189 10.819 12.775 11.265 12.244 11.589C11.72 11.914 11.133 12.077 10.488 12.077C9.968 12.077 9.481 11.968 9.03 11.751C8.7 11.593 8.406 11.388 8.149 11.138V14.235C8.149 14.465 8.077 14.666 7.924 14.819C7.771 14.972 7.571 15.043 7.34 15.043C7.116 15.043 6.92 14.97 6.761 14.822C6.604 14.666 6.533 14.465 6.533 14.235V8.353C6.533 7.658 6.694 7.026 7.017 6.459C7.348 5.886 7.792 5.438 8.348 5.115C8.914 4.782 9.543 4.617 10.23 4.617Z" fill="white"></path></svg> </div> <span class="hd-pr-name">pie</span> <span class="hd-pr-bot">BOT</span> <span class="hd-pr-flex"></span> <span class="hd-pr-time">opened just now</span> </div> <div class="hd-pr-title" data-r="0.2">fix: reset loading state so Proceed to cart stays clickable</div> <div class="hd-pr-block" data-r="0.4"> <div class="hd-pr-label">ROOT CAUSE</div> <div class="hd-pr-text"><code class="hd-pr-inline">handleClick()</code> sets <code class="hd-pr-inline">loading</code> to true but never resets it — button stays disabled after the first click.</div> </div> <div class="hd-pr-block" data-r="0.6"> <div class="hd-pr-label">FIX APPLIED</div> <div class="hd-pr-code"><span class="hd-pr-code-plus">+</span>await addItem(product); setLoading(false);</div> </div> <div class="hd-pr-badges" data-r="0.8"> <span class="hd-pr-badge hd-pr-badge--green"><span class="hd-pr-badge-ck">✓</span> CI passing</span> <span class="hd-pr-badge hd-pr-badge--blue"><span class="hd-pr-badge-ck">✓</span> Ready to merge</span> </div> </div> </div> </div> </div> <!-- Cursor — hidden during scene 2 (Lottie has its own) --> <div class="hd-cursor" id="hd-cursor" aria-hidden="true"> <svg width="22" height="26" viewBox="0 0 22 26" fill="none"> <path d="M2 1.2V22.5l5.3-5 3.6 7.2 3-1.5-3.5-7.1 7.5-.5L2 1.2Z" fill="#fff" stroke="#6B21A8" stroke-width="1.3" stroke-linejoin="round"></path> </svg> <div class="hd-cursor-label" id="hd-cursor-label"></div> <div class="hd-cursor-pulse" id="hd-cursor-pulse"></div> </div> <!-- Bottom status bar --> <div class="hd-statusbar"> <span class="hd-statusbar-dot" id="hd-statusbar-dot"></span> <span class="hd-statusbar-text" id="hd-statusbar-text">Pie is reading the diff</span> <span class="hd-statusbar-flex"></span> <span class="hd-statusbar-brand">pie · autonomous qa</span> </div> </div> </div> </div> </div></div> </section> <script>
(function() {
  var wrap = document.getElementById('hd-wrap');
  if (!wrap) return;

  // ── Scale-to-fit ─────────────────────────────────────────────
  // The demo keeps its native 640px geometry (all cursor path coordinates
  // depend on it) and scales down via transform to whatever width the hero
  // artifact column provides — desktop column and mobile alike. JS drives
  // `transform: scale()` + compensating shell height. Runs on init, on
  // resize, and after fonts load (layout can shift as Martian Mono
  // replaces the fallback font).
  var shell = wrap.parentElement;
  var NATIVE_W = 640;
  function fitDemo() {
    if (!shell) return;
    // < 360px = CSS media-query renders the static scene-3 poster; skip JS.
    if (window.matchMedia('(max-width: 359px)').matches) {
      wrap.style.transform = '';
      shell.style.height = '';
      return;
    }
    var avail = shell.clientWidth;
    if (avail >= NATIVE_W) {
      wrap.style.transform = '';
      shell.style.height = '';
      return;
    }
    // Reset transform AND clear any prior shell height before measuring.
    // A stale shell height can constrain the wrap's layout and produce a
    // bogus naturalH on the next read.
    wrap.style.transform = '';
    shell.style.height = '';
    // Force synchronous reflow so the height read reflects unscaled layout.
    void wrap.offsetWidth;
    var naturalH = wrap.getBoundingClientRect().height;
    var scale = avail / NATIVE_W;
    wrap.style.transform = 'scale(' + scale + ')';
    // +2 compensates the artifact card's own border (border-box sizing);
    // Math.ceil so we never undershoot and clip the status bar.
    shell.style.height = (Math.ceil(naturalH * scale) + 2) + 'px';
  }
  fitDemo();
  // Reveal the wrap — mobile CSS keeps it visibility:hidden until now so
  // viewers never see the unscaled 640px layout flash.
  wrap.classList.add('hd-ready');
  // rAF-gate resize: one fitDemo call per animation frame is plenty.
  var resizeRaf = 0;
  window.addEventListener('resize', function() {
    if (resizeRaf) return;
    resizeRaf = requestAnimationFrame(function() {
      resizeRaf = 0;
      fitDemo();
    });
  });
  if (document.fonts && document.fonts.ready) {
    document.fonts.ready.then(fitDemo);
  }

  // Note: we intentionally do NOT bail on `prefers-reduced-motion: reduce`.
  // iOS 17+ Safari reports that media query as `reduce` whenever Low Power
  // Mode is on, which silently froze the hero animation for any visitor on
  // low battery — the dominant case for mobile traffic. The hero IS the
  // page's main visual story, so we keep it running unconditionally.

  // Poster on very narrow viewports (<360px = static scene-3 poster).
  var narrow = window.matchMedia('(max-width: 359px)');
  if (narrow.matches) return;

  // ── Element lookups ──
  var scenes = wrap.querySelectorAll('.hd-scene');
  var pills = wrap.querySelectorAll('.hd-pill');
  var conns = wrap.querySelectorAll('.hd-conn');
  var pillRings = wrap.querySelectorAll('.hd-pill-ring');
  var connFills = wrap.querySelectorAll('.hd-conn-fill');
  var codeTrack = document.getElementById('hd-code-track');
  var codeScan = document.getElementById('hd-code-scan');
  var s1Status = document.getElementById('hd-s1-status');
  var cursor = document.getElementById('hd-cursor');
  var cursorLabel = document.getElementById('hd-cursor-label');
  var cursorPulse = document.getElementById('hd-cursor-pulse');
  var statusbarDot = document.getElementById('hd-statusbar-dot');
  var statusbarText = document.getElementById('hd-statusbar-text');
  var prRevealEls = wrap.querySelectorAll('[data-r]');

  // ── Timing constants ──
  var CYCLE = 17000;
  var P1 = [0, 5500];
  var P2 = [5500, 11000];
  var P3 = [11000, 17000];

  // Code diff geometry — container height 240, line height 22. CODE_TOTAL
  // is the rendered track height; line 16 wraps at the editor's width so
  // we measure it at runtime (below) to stay robust against font-load
  // shifts and width tweaks.
  var CODE_CONTAINER = 240;
  var CODE_TOTAL = 17 * 22;

  // ── Per-tick state cache to avoid needless DOM writes ──
  var last = {
    active: -1, sceneTx: [null, null, null], sceneOp: [null, null, null],
    scrollProg: -1, criticalLit: null, statusText: '',
    p2Prog: -1, reveal: -1,
    cursorCx: NaN, cursorCy: NaN, cursorLabel: '', cursorHidden: null, cursorPulse: null,
    barText: '', barColor: '',
    pillStates: ['', '', ''], pillRings: [-1, -1, -1], connFills: [-1, -1]
  };

  // ── Helpers ──
  function clamp(v, lo, hi) { return v < lo ? lo : v > hi ? hi : v; }

  function sceneOffset(n, t, active) {
    if (active === n) {
      var localStart = n === 1 ? P1[0] : n === 2 ? P2[0] : P3[0];
      var since = t - localStart;
      if (since < 500) return { tx: (1 - since / 500) * 40, op: since / 500 };
      return { tx: 0, op: 1 };
    }
    return { tx: active > n ? -40 : 40, op: 0 };
  }

  // ── Cursor path ──
  function cursorPath(t, active, scrollProg, criticalLit, reveal) {
    var cx = 0, cy = 0, label = '', hidden = false, pulse = false;
    var pillY = 50;
    if (t < 400) {
      cx = 330; cy = pillY; label = '';
    } else if (t < P1[1] - 300) {
      if (criticalLit) {
        // Park the cursor at line 16's wrapped continuation row, where the
        // `loading` token actually lives after the line wraps.
        cx = 190; cy = 238;
      } else {
        cx = 180 + scrollProg * 90; cy = 180 + scrollProg * 55;
      }
      label = criticalLit ? 'button stuck disabled' : 'reading code';
      pulse = !!criticalLit;
    } else if (t < P2[0] + 500) {
      cx = 420; cy = pillY; label = 'next →';
    } else if (t < P2[1] - 300) {
      // Hidden during scene 2 — Lottie shows its own cursor
      hidden = true;
    } else if (t < P3[0] + 500) {
      cx = 500; cy = pillY; label = '→';
    } else {
      cx = 340 + reveal * 100; cy = 250 + reveal * 70; label = 'writing PR';
    }
    return { cx: cx, cy: cy, label: label, hidden: hidden, pulse: pulse };
  }

  // ── Step pills + connectors ──
  function paintPills(active, progress) {
    var p = clamp(progress, 0, 1);
    for (var i = 0; i < pills.length; i++) {
      var n = i + 1;
      var state = n === active ? 'active' : (n < active ? 'done' : 'upcoming');
      if (last.pillStates[i] !== state) {
        pills[i].setAttribute('data-state', state);
        last.pillStates[i] = state;
      }
      var deg = n === active ? Math.round(p * 360) : (n < active ? 360 : 0);
      if (last.pillRings[i] !== deg) {
        pillRings[i].style.setProperty('--ring-deg', deg + 'deg');
        last.pillRings[i] = deg;
      }
    }
    for (var j = 0; j < conns.length; j++) {
      var connN = j + 1; // connector after pill connN
      var fill;
      if (active > connN) fill = 1;
      else if (active === connN) fill = p;
      else fill = 0;
      if (last.connFills[j] !== fill) {
        conns[j].setAttribute('data-state', active > connN ? 'done' : active === connN ? 'active' : 'upcoming');
        connFills[j].style.width = (fill * 100) + '%';
        last.connFills[j] = fill;
      }
    }
  }

  // ── Scene 1 paint ──
  function paintScene1(scrollProg, criticalLit) {
    if (last.scrollProg !== scrollProg) {
      var scroll = Math.max(0, scrollProg * (CODE_TOTAL - CODE_CONTAINER + 40));
      codeTrack.style.transform = 'translateY(' + (-scroll) + 'px)';
      // Scan line follows the bottom of the visible window
      var top = scrollProg > 0
        ? Math.min(CODE_CONTAINER - 4, Math.min(scrollProg, 1) * CODE_CONTAINER - 2)
        : 0;
      codeScan.style.top = top + 'px';
      last.scrollProg = scrollProg;
    }
    if (last.criticalLit !== criticalLit) {
      codeTrack.setAttribute('data-crit', criticalLit ? '1' : '0');
      codeScan.setAttribute('data-crit', criticalLit ? '1' : '0');
      last.criticalLit = criticalLit;
    }
    var statusText = criticalLit
      ? '⚠ button blocked on line 16'
      : 'scanning · ' + Math.floor(scrollProg * 100) + '%';
    if (last.statusText !== statusText) {
      s1Status.textContent = statusText;
      s1Status.setAttribute('data-alert', criticalLit ? '1' : '0');
      last.statusText = statusText;
    }
  }

  // ── Scene 2 paint — Lottie scrubbing ──
  function paintScene2(p2Prog, active) {
    if (active !== 2) return;
    var anim = window.__pieLottieAnim;
    if (!anim || !window.__pieLottieReady) return;
    var total = anim.totalFrames || 0;
    if (total <= 0) return;
    // Skip when progress barely changed (≈1 frame on a 324-frame Lottie).
    // Each goToAndStop triggers a full SVG re-render, so rate-limiting this
    // is the biggest per-tick win on low-end devices.
    if (Math.abs(p2Prog - last.p2Prog) < 0.003) return;
    last.p2Prog = p2Prog;
    anim.goToAndStop(clamp(p2Prog * (total - 1), 0, total - 1), true);
  }

  // ── Scene 3 paint — staggered reveals ──
  function paintScene3(reveal) {
    if (last.reveal === reveal) return;
    last.reveal = reveal;
    for (var i = 0; i < prRevealEls.length; i++) {
      var el = prRevealEls[i];
      var thr = parseFloat(el.getAttribute('data-r'));
      el.classList.toggle('hd-reveal-on', reveal >= thr);
    }
  }

  // ── Cursor paint ──
  // The cursor moves on a critically-damped spring toward the waypoint the
  // path function returns. The old approach (CSS `transition: transform .5s`
  // retargeted by per-frame transform writes) restarted the easing curve
  // every frame while the target drifted, which read as rubbery stutter.
  // The spring carries velocity across waypoint changes, so drift segments
  // and jumps blend into one continuous, eased motion.
  var sprOmega = 12; // rad/s — ~0.5s settle, matches the old transition tempo
  var spr = { x: 0, y: 0, vx: 0, vy: 0, on: false };
  function springAxis(p, v, target, dt) {
    // exact critically-damped solution: stable for any dt (tab-resume safe)
    var e = Math.exp(-sprOmega * dt);
    var dx = p - target;
    var k = (v + sprOmega * dx) * dt;
    return [target + (dx + k) * e, (v - sprOmega * k) * e];
  }
  function paintCursor(t, dt, active, scrollProg, criticalLit, reveal) {
    var cp = cursorPath(t, active, scrollProg, criticalLit, reveal);
    if (last.cursorHidden !== cp.hidden) {
      cursor.style.opacity = cp.hidden ? '0' : '1';
      last.cursorHidden = cp.hidden;
    }
    if (cp.hidden) { spr.on = false; return; }
    if (!spr.on) {
      // first frame, or re-entering after scene 2 hid it: appear in place
      spr.on = true; spr.x = cp.cx; spr.y = cp.cy; spr.vx = 0; spr.vy = 0;
    } else {
      var sx = springAxis(spr.x, spr.vx, cp.cx, dt);
      var sy = springAxis(spr.y, spr.vy, cp.cy, dt);
      spr.x = sx[0]; spr.vx = sx[1];
      spr.y = sy[0]; spr.vy = sy[1];
    }
    var wx = Math.round(spr.x * 100) / 100;
    var wy = Math.round(spr.y * 100) / 100;
    if (last.cursorCx !== wx || last.cursorCy !== wy) {
      cursor.style.transform = 'translate3d(' + wx + 'px,' + wy + 'px,0)';
      last.cursorCx = wx; last.cursorCy = wy;
    }
    if (last.cursorLabel !== cp.label) {
      if (cp.label) {
        cursorLabel.textContent = cp.label;
        cursorLabel.style.opacity = '1';
      } else {
        cursorLabel.style.opacity = '0';
      }
      last.cursorLabel = cp.label;
    }
    if (last.cursorPulse !== cp.pulse) {
      cursorPulse.style.opacity = cp.pulse ? '1' : '0';
      last.cursorPulse = cp.pulse;
    }
  }

  // ── Bottom status bar ──
  // Semantic colors from the redesign vocabulary:
  // blue = code/info, pink = bug, green = pass.
  var BAR_TEXT = {
    1: 'Pie is reading the diff',
    2: 'Pie is running your app',
    3: 'Pie is opening a fix PR'
  };
  var BAR_COLOR = {
    1: '#2BA6EE',
    2: '#EC4899',
    3: '#17A673'
  };
  function paintBar(active) {
    var txt = BAR_TEXT[active];
    var clr = BAR_COLOR[active];
    if (last.barText !== txt) {
      statusbarText.textContent = txt;
      last.barText = txt;
    }
    if (last.barColor !== clr) {
      statusbarDot.style.background = clr;
      statusbarDot.style.boxShadow = '0 0 8px ' + clr;
      last.barColor = clr;
    }
  }

  // ── Scene push/pop ──
  function paintScenes(t, active) {
    for (var i = 0; i < scenes.length; i++) {
      var n = i + 1;
      var off = sceneOffset(n, t, active);
      if (last.sceneTx[i] !== off.tx || last.sceneOp[i] !== off.op) {
        scenes[i].style.transform = 'translateX(' + off.tx + 'px)';
        scenes[i].style.opacity = off.op;
        scenes[i].classList.toggle('hd-scene--active', n === active);
        last.sceneTx[i] = off.tx; last.sceneOp[i] = off.op;
      }
    }
  }

  // Measure the actual rendered code-track height so the scroll formula
  // accounts for whatever wrapping happens at the editor's width. Runs
  // once now (DOM ready) and again when fonts finish loading, since text
  // metrics shift between fallback fonts and Martian Mono.
  function measureCodeTotal() {
    if (!codeTrack) return;
    // Subtract the 10px top + 10px bottom padding on the track.
    var h = codeTrack.offsetHeight - 20;
    if (h > 0) CODE_TOTAL = h;
  }
  measureCodeTotal();
  if (document.fonts && document.fonts.ready) {
    document.fonts.ready.then(measureCodeTotal);
  }

  // ── Main rAF loop ──
  var start = performance.now();
  var prevNow = start;
  function tick(now) {
    var dt = Math.min(0.1, Math.max(0, (now - prevNow) / 1000));
    prevNow = now;
    var t = (now - start) % CYCLE;
    var active = t < P1[1] ? 1 : t < P2[1] ? 2 : 3;
    var p1t = t - P1[0];
    var p2t = t - P2[0];
    var p3t = t - P3[0];
    var scrollProg = clamp(p1t / 3500, 0, 1);
    var criticalLit = p1t > 3200 && t < P1[1];
    var p2Prog = clamp(p2t / (P2[1] - P2[0]), 0, 1);
    var reveal = clamp(p3t / 2800, 0, 1);

    if (last.active !== active) {
      last.active = active;
    }

    paintScenes(t, active);
    paintScene1(scrollProg, criticalLit);
    paintScene2(p2Prog, active);
    paintScene3(reveal);
    paintCursor(t, dt, active, scrollProg, criticalLit, reveal);
    paintBar(active);
    paintPills(active, active === 1 ? scrollProg : active === 2 ? p2Prog : reveal);

    requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
})();
</script> <script type="module">
  // Lottie (scene 2) — lottie-web's SVG renderer for clean frame scrubbing
  // (goToAndStop). Exposed on window.__pieLottieAnim so the rAF loop can
  // scrub in sync with p2Prog.
  import lottie from 'https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/+esm';
  const container = document.getElementById('hd-lottie');
  if (container) {
    const anim = lottie.loadAnimation({
      container,
      renderer: 'svg',
      loop: false,
      autoplay: false,
      path: '/lottie/pie-panel2-checkout.json',
      rendererSettings: {
        preserveAspectRatio: 'xMidYMid meet',
        progressiveLoad: true,
      },
    });
    window.__pieLottieAnim = anim;
    anim.addEventListener('DOMLoaded', () => { window.__pieLottieReady = true; });
  }
</script> <!-- PROOF: static logo wall. Hairline grid, label in the center cell.
     Cells with a case study link to it (tag appears on hover); last cell routes to /customers/. --><div class="proof"> <div class="wrap"> <div class="lw-grid"> <a class="lw-cell lw-link" href="/customers/fi/"> <img src="/redesign/logos-color/fi.svg" alt="Fi" style="height:30px"> <span class="lw-tag">Case study →</span> </a> <div class="lw-cell"><img src="/redesign/logos-color/tilt.svg" alt="Tilt" style="height:26px"></div> <div class="lw-cell"><img src="/redesign/logos-color/redpoints.svg" alt="Red Points" style="height:26px"></div> <div class="lw-cell"><img src="/redesign/logos-color/dsg.svg" alt="Dick's Sporting Goods" style="height:34px"></div> <div class="lw-cell"><img src="/redesign/logos-color/spark.png" alt="Spark Inventory" style="height:26px"><span class="lw-name">Spark Inventory</span></div> <div class="lw-cell lw-label">Trusted by teams that<br>ship fast and break nothing</div> <div class="lw-cell"><img src="/redesign/logos-color/lumo.svg" alt="Lumo" style="height:24px"></div> <div class="lw-cell"><img src="/redesign/logos-color/prado.svg" alt="Prado" style="height:26px"></div> <div class="lw-cell"><img src="/redesign/logos-color/focal.png" alt="Focal" style="height:24px"></div> <div class="lw-cell"><img src="/redesign/logos-color/fairway.svg" alt="Fairway" style="height:15px"></div> <a class="lw-cell lw-more" href="/customers/">More customers <span class="ar">→</span></a> </div> </div> </div> <!-- PROBLEM (copy + exec-channel artifact up top; dead-ends at display scale below) --><section class="pad problem-sec" style="padding-bottom:40px"><div class="wrap"> <div class="prob-top"> <div class="prob-copy"> <div class="eyebrow">The problem</div> <h2>Velocity keeps climbing. Quality keeps <span class="slip-word">slipping.</span></h2> <p class="lede">You find out from a customer, or a screenshot in the exec channel. Either way, you're the one explaining why.</p> </div> <div class="exec-card" aria-hidden="true"> <div class="ec-chan"># exec</div> <div class="ec-msg"> <span class="ec-ava">VS</span> <div class="ec-body"> <div class="ec-meta"><b>VP Sales</b><span>9:47 AM</span></div> <p>is checkout broken on iOS?? 3 customers just pinged me</p> <div class="ec-shot"> <span class="ecs-bar ecs-nav"></span> <span class="ecs-bar w70"></span> <span class="ecs-bar w45"></span> <span class="ecs-btn">Proceed to cart<span class="ec-alert">!</span></span> </div> <div class="ec-foot"><span class="ec-react">😬 3</span><span class="ec-react">👀 2</span><span class="ec-replies">6 replies</span></div> </div> </div> </div> </div> <div class="shead" style="text-align:center"> <div class="bigq">So: <span class="hlq">what are you going to do about it?</span></div> <ul class="deadends" role="list"> <li class="de-row"><span class="de-opt">Hire QA?</span><span class="de-out">MONTHS TO RAMP, STILL OUTPACED</span></li> <li class="de-row"><span class="de-opt">Write more scripts?</span><span class="de-out">FLAKY, THEN ABANDONED</span></li> <li class="de-row"><span class="de-opt">Let Claude test itself?</span><span class="de-out">WORKS ONCE, NOT EVERY PUSH</span></li> </ul> <div class="kick"><span class="k2">You need something that just fixes it.</span></div> <div class="connector" aria-hidden="true"></div> </div> </div></section> <!-- REFRAME (ripple #2 — the one dark moment) --><section class="reframe"> <svg class="crust top" id="crustTop" preserveAspectRatio="none"></svg> <canvas class="rip" id="dotCanvas"></canvas> <div class="warmglow" aria-hidden="true"></div> <svg class="sparks" viewBox="0 0 1200 600" aria-hidden="true" style="position:absolute;inset:0;width:100%;height:100%;z-index:1;pointer-events:none;"></svg> <svg class="crust bot" id="crustBot" preserveAspectRatio="none"></svg> <div class="wrap"> <div class="eyebrow">Meet Pie</div> <h2>Pie finds and fixes bugs<br>in the background. <span class="auto-word"><span class="aw-txt">Automatically.</span><span class="sp sp1" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="M7 0 L8.7 5.3 L14 7 L8.7 8.7 L7 14 L5.3 8.7 L0 7 L5.3 5.3 Z" fill="#FBBF24"></path></svg></span><span class="sp sp2" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="M7 0 L8.7 5.3 L14 7 L8.7 8.7 L7 14 L5.3 8.7 L0 7 L5.3 5.3 Z" fill="#fff"></path></svg></span><span class="sp sp3" aria-hidden="true"><svg viewBox="0 0 14 14"><path d="M7 0 L8.7 5.3 L14 7 L8.7 8.7 L7 14 L5.3 8.7 L0 7 L5.3 5.3 Z" fill="#FBBF24"></path></svg></span></span></h2> <p class="r1">It runs quietly in the background, using your product the way your customers do, reaching the coverage manual can't staff and scripts can't maintain.</p> <p class="r2">You wake up to <span class="fx">fix PRs</span>, not bug reports.</p> <p class="r3">Like a Roomba for your product quality.</p> </div> </section> <!-- TESTIMONIAL — two company dossiers: everything about a customer lives in one panel.
     Header = logo + outcome chip (who + result at a glance), quote is the texture,
     person authenticates, footer routes to the case study.
     Fi = the speed story (days to hours), Tilt = the toil story (manual regression gone).
     Quotes approved: Bensamoun (CONTENT.md canonical), Lekkalapudi (signed off, PR #232). --><section class="pad" id="testimonials" style="background:#fbfafe;background-image:radial-gradient(rgba(107,33,168,.16) 1px,transparent 1px);background-size:26px 26px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);overflow:hidden;"> <div class="wrap" style="position:relative;z-index:2;"> <div class="shead"><div class="eyebrow">The proof</div><h2>Confidence to ship<br><span class="hlf">fast &amp; furious.</span></h2></div> <div class="tduo"> <div class="tco"> <div class="tco-hd"> <img class="tco-logo" src="/redesign/logos-color/fi.svg" alt="Fi" loading="lazy"> <div class="tco-chip"><b>days → hours</b><span>release testing</span></div> </div> <blockquote class="tco-q lg">"Pie has helped us elevate our level of confidence, and the speed at which we can release new products."</blockquote> <div class="who-row"> <img class="who-ava" src="/screenshots/jon-fi.avif" alt="Jonathan Bensamoun" loading="lazy"> <span class="who-meta"><b>Jonathan Bensamoun</b><span>CEO</span></span> </div> <a class="tco-link" href="/customers/fi/">Read the Fi case study <span class="ar">→</span></a> </div> <div class="tco"> <div class="tco-hd"> <img class="tco-logo" src="/redesign/logos-color/tilt.svg" alt="Tilt" loading="lazy"> <div class="tco-chip"><b>0 manual regression</b><span>5 apps · 3 markets</span></div> </div> <blockquote class="tco-q">"After evaluating multiple vendors, Pie was the only solution that consistently executed our most complex end-to-end workflows with reliability across builds. It has effectively replaced our manual regression efforts, enabling us to maintain our release velocity with significantly greater efficiency and confidence."</blockquote> <div class="who-row"> <span class="who-ava init" aria-hidden="true">AL</span> <span class="who-meta"><b>Anil Kumar Lekkalapudi</b><span>Director of QA &amp; Automation</span></span> </div> <a class="tco-link" href="/customers/">More customer stories <span class="ar">→</span></a> </div> </div> </div></section> <!-- HOW (the graph IS the section: trace carries the steps, text hangs off the nodes) --><section class="pad hiw"> <div class="wrap"> <div class="shead"><div class="eyebrow">How it works</div><h2>Quality on autopilot, on every push.</h2></div> </div> <svg class="wf-trace" id="wfTrace"></svg> <div class="wrap"> <div class="steps"> <svg class="wf-trace-v" id="wfTraceV"></svg> <div class="step"><h3>Explores your product</h3><p>Maps your real user flows. No test scripts to write.</p></div> <div class="step"><h3>Tests every change</h3><p>Reads every PR and exercises it the way your users will.</p></div> <div class="step"><h3>Catches what breaks</h3><p>Functional and usability bugs. Not pass/fail theater.</p></div> <div class="step"><h3>Ships the fix</h3><p>Opens a PR with the fix, ready to review. Not more homework.</p></div> </div> </div> </section> <!-- THE APPROACH: vision vs AI-generated scripts. Split-view artifact proves the mechanism:
     a script's assertions all pass while the screen is visibly broken. The two panels mirror
     zone for zone (screen, readout, verdict) so the difference reads by comparing same spots. --><section class="pad whypie"><div class="wrap"> <div class="shead wp-head"> <div class="eyebrow">The approach</div> <h2>Scripts are not sufficient.</h2> <p class="lede">If scripts were sufficient, this problem would be solved by now. Instead, AI is cranking out more scripts than ever and quality is still dropping.</p> </div> <div class="sv-grid"> <div class="sv-col sv-script"> <div class="sv-who"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.9 5.1A9.8 9.8 0 0 1 12 4.9c5.2 0 8.6 4.3 9.7 6.6a1.1 1.1 0 0 1 0 1c-.5 1-1.6 2.7-3.3 4M6.2 6.9C4 8.4 2.8 10.4 2.3 11.5a1.1 1.1 0 0 0 0 1c1.1 2.3 4.5 6.6 9.7 6.6 1.5 0 2.9-.4 4.1-1"></path><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"></path><line x1="3.5" y1="3.5" x2="20.5" y2="20.5"></line></svg>WHAT A SCRIPT SEES</div> <div class="ph-wrap" aria-hidden="true"> <div class="phone wire"> <div class="ph-status"><span class="wf-bar s"></span><span class="ph-island"></span><span class="wf-bar s"></span></div> <div class="ph-title"><span class="wf-bar hd"></span></div> <div class="ph-toast"><span class="wf-bar tst"></span></div> <div class="ph-empty"><span class="dev-box"><em>.cart-items</em></span><span class="wf-cart"></span><span class="wf-bar b1"></span></div> <div class="ph-tabs"><span class="wf-tab"></span><span class="wf-tab"></span><span class="wf-tab bdg"><span class="wf-dot"></span><span class="dev-box db"><em>#cart-badge</em></span></span></div> </div> <div class="sv-term"> <div><span class="ok">✓</span>click('#add-to-cart')</div> <div><span class="ok">✓</span>expect(status).toBe(200)</div> <div><span class="ok">✓</span>expect(badge).toBe('1')</div> </div> </div> <div class="sv-pass">PASS · 3 of 3 assertions</div> </div> <div class="sv-col sv-pie"> <div class="sv-who"><svg class="pie-eye" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.3 11.5C3.4 9.2 6.8 4.9 12 4.9s8.6 4.3 9.7 6.6a1.1 1.1 0 0 1 0 1c-1.1 2.3-4.5 6.6-9.7 6.6s-8.6-4.3-9.7-6.6a1.1 1.1 0 0 1 0-1Z"></path><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"></circle></svg>WHAT PIE SEES</div> <div class="ph-wrap"> <div class="phone live"> <div class="ph-status"><span class="ph-time">9:41</span><span class="ph-island"></span><span class="ph-sig"><i></i><i></i></span></div> <div class="ph-title">Cart</div> <div class="ph-toast ok"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.5 12.5l5 5 10-11"></path></svg>Added to cart</div> <div class="ph-empty"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9.5" cy="20" r="1.3"></circle><circle cx="16.5" cy="20" r="1.3"></circle><path d="M3.5 4.5h2.2l2.1 11h10L20.5 8.2H6.6"></path></svg>Your cart is empty.</div> <div class="ph-tabs"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true"><path d="M4 11.2 12 4.4l8 6.8V20h-5.6v-4.8h-4.8V20H4z"></path></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="10.7" cy="10.7" r="6.2"></circle><line x1="15.3" y1="15.3" x2="20" y2="20"></line></svg> <span class="tb-cart"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9.5" cy="20" r="1.3"></circle><circle cx="16.5" cy="20" r="1.3"></circle><path d="M3.5 4.5h2.2l2.1 11h10L20.5 8.2H6.6"></path></svg><span class="ph-badge">1</span></span> </div> <div class="gaze" aria-hidden="true"></div> </div> <span class="ph-note n-items">actually empty</span> <span class="ph-note n-badge">says 1 item</span> </div> <div class="sv-flag">FLAGGED · a real user hits this</div> </div> </div> <div class="bigq wp-kicker"><span class="k-dead">The code worked.</span><span class="k-live"><span class="hlq">The experience didn't.</span></span></div> <div class="wp-segue eyebrow">Here's what makes Pie different</div> <!-- one object: pillars are cells in a hairline grid, the platform row is its footer --> <div class="wp-card"> <div class="wp-pillar"> <div class="wp-k" style="color:var(--blue)">NO SELECTORS</div> <h3>No more flakes</h3> <p>Pie finds the button by looking at the screen, like a user does. Redesign the UI and coverage keeps working.</p> </div> <div class="wp-pillar"> <div class="wp-k" style="color:var(--pink)">REAL JUDGMENT</div> <h3>Catches what scripts pass</h3> <p>Status code 200 is not a working product. Pie catches the broken experience behind the passing check.</p> </div> <div class="wp-pillar"> <div class="wp-k" style="color:var(--green)">SIGNAL, NOT NOISE</div> <h3>Pinged only when it's real</h3> <p>Every finding is reproduced before it reaches you. Three real bugs, not three hundred maybes.</p> </div> </div> <!-- platform rail: same eyebrow rank as the pillars group. Real brand marks, no sentence. --> <div class="wp-run"> <div class="wp-segue eyebrow">Runs where your users are</div> <div class="wp-os"> <span class="wpp-cell"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"></path></svg>iOS</span> <span class="wpp-cell"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M18.4395 5.5586c-.675 1.1664-1.352 2.3318-2.0274 3.498-.0366-.0155-.0742-.0286-.1113-.043-1.8249-.6957-3.484-.8-4.42-.787-1.8551.0185-3.3544.4643-4.2597.8203-.084-.1494-1.7526-3.021-2.0215-3.4864a1.1451 1.1451 0 0 0-.1406-.1914c-.3312-.364-.9054-.4859-1.379-.203-.475.282-.7136.9361-.3886 1.5019 1.9466 3.3696-.0966-.2158 1.9473 3.3593.0172.031-.4946.2642-1.3926 1.0177C2.8987 12.176.452 14.772 0 18.9902h24c-.119-1.1108-.3686-2.099-.7461-3.0683-.7438-1.9118-1.8435-3.2928-2.7402-4.1836a12.1048 12.1048 0 0 0-2.1309-1.6875c.6594-1.122 1.312-2.2559 1.9649-3.3848.2077-.3615.1886-.7956-.0079-1.1191a1.1001 1.1001 0 0 0-.8515-.5332c-.5225-.0536-.9392.3128-1.0488.5449zm-.0391 8.461c.3944.5926.324 1.3306-.1563 1.6503-.4799.3197-1.188.0985-1.582-.4941-.3944-.5927-.324-1.3307.1563-1.6504.4727-.315 1.1812-.1086 1.582.4941zM7.207 13.5273c.4803.3197.5506 1.0577.1563 1.6504-.394.5926-1.1038.8138-1.584.4941-.48-.3197-.5503-1.0577-.1563-1.6504.4008-.6021 1.1087-.8106 1.584-.4941z"></path></svg>Android</span> <span class="wpp-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="9"></circle><ellipse cx="12" cy="12" rx="4" ry="9"></ellipse><line x1="3.6" y1="9.5" x2="20.4" y2="9.5"></line><line x1="3.6" y1="14.5" x2="20.4" y2="14.5"></line></svg>Web</span> </div> <div class="wpf"> <span class="wpf-chip"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M13.543 3.41c4.114 2.47 6.545 7.162 5.549 11.131-.024.093-.05.181-.076.272l.002.001c2.062 2.538 1.5 5.258 1.236 4.745-1.072-2.086-3.066-1.568-4.088-1.043a6.803 6.803 0 0 1-.281.158l-.02.012-.002.002c-2.115 1.123-4.957 1.205-7.812-.022a12.568 12.568 0 0 1-5.64-4.838c.649.48 1.35.902 2.097 1.252 3.019 1.414 6.051 1.311 8.197-.002C9.651 12.73 7.101 9.67 5.146 7.191a10.628 10.628 0 0 1-1.005-1.384c2.34 2.142 6.038 4.83 7.365 5.576C8.69 8.408 6.208 4.743 6.324 4.86c4.436 4.47 8.528 6.996 8.528 6.996.154.085.27.154.36.213.085-.215.16-.437.224-.668.708-2.588-.09-5.548-1.893-7.992z"></path></svg>Swift</span> <span class="wpf-chip"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M24 24H0V0h24L12 12Z"></path></svg>Kotlin</span> <span class="wpf-chip"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M24 24H0V0h24L12 12Z"></path></svg>Kotlin Multiplatform</span> <span class="wpf-chip"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"></path></svg>React Native</span> <span class="wpf-chip"><svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M14.314 0L2.3 12 6 15.7 21.684.013h-7.357zm.014 11.072L7.857 17.53l6.47 6.47H21.7l-6.46-6.468 6.46-6.46h-7.37z"></path></svg>Flutter</span> <span class="wpf-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="3" y="4.5" width="18" height="15" rx="2.4"></rect><line x1="3" y1="9" x2="21" y2="9"></line><circle cx="6" cy="6.8" r=".4" fill="currentColor"></circle><circle cx="8.4" cy="6.8" r=".4" fill="currentColor"></circle></svg>Webviews</span> </div> </div> </div> </section> <!-- OTHER ROUTES: not competitors, other ways to solve the problem.
     Master-detail: a segmented selector rail on the left, panel mirrors on the right
     (accordion on mobile). main.js clones each .alt-detail into #altPanel, so the
     .ad-head inside each detail is carried into the panel for free.
     Breakdown per route: verdict · keep it for · where it stops · receipt · with Pie. --><section class="pad altroutes"><div class="wrap"> <div class="shead"> <div class="eyebrow">Other routes</div> <h2>Other ways you could solve this.</h2> <p class="lede">Not competitors. Different layers of the same problem, and where each one runs out.</p> </div> <div class="alt-md"> <div class="alt-stack" role="tablist" aria-label="Alternative approaches"> <div class="avi" role="tab" tabindex="0" aria-selected="false"> <span class="rt-chip"><svg class="rt-glyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><polyline points="9.5 13 8 14.5 9.5 16"></polyline><polyline points="14.5 13 16 14.5 14.5 16"></polyline></svg></span> <div class="rt-tx"> <span class="lyr-k">RUNS SCRIPTS</span> <b>Playwright / Appium</b> <span class="lyr-d">Break on UI changes. Assert only what you predicted.</span> </div> <div class="alt-detail"> <div class="ad-head"> <span class="ad-head-glyph"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><polyline points="9.5 13 8 14.5 9.5 16"></polyline><polyline points="14.5 13 16 14.5 14.5 16"></polyline></svg></span> <b>Playwright / Appium</b> <span class="ad-head-k">RUNS SCRIPTS</span> </div> <div class="ad-verdict">Playwright gives you precision. It can't give you judgment.</div> <div class="ad-cols"> <div class="ad-col keep"><span class="ad-lbl">Keep it for</span><p>Deterministic checks on critical paths, owned by engineers who want that control.</p></div> <div class="ad-col stop"><span class="ad-lbl">Where it stops</span><p>Every UI change is selector churn. A green run only means the selectors resolved. Checkout can render $0.00 and still pass.</p></div> </div> <div class="receipt"><span class="rc-ok">✓ 214 passed · 0 failed</span><span class="rc-bad">✕ checkout renders $0.00</span></div> <div class="ad-pie"><span class="ad-lbl">With Pie</span><p>Runs alongside your suite, tests like a user, and there's nothing to maintain. <a href="/comparisons/pie-vs-selenium/">Full comparison →</a></p></div> </div> </div> <div class="avi" role="tab" tabindex="0" aria-selected="false"> <span class="rt-chip"><svg class="rt-glyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"></circle><line x1="15.3" y1="15.3" x2="21" y2="21"></line><line x1="8" y1="9" x2="13" y2="9"></line><line x1="8" y1="12" x2="11.5" y2="12"></line></svg></span> <div class="rt-tx"> <span class="lyr-k">READS CODE</span> <b>CodeRabbit / Greptile</b> <span class="lyr-d">Reads the diff. Never runs the app.</span> </div> <div class="alt-detail"> <div class="ad-head"> <span class="ad-head-glyph"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"></circle><line x1="15.3" y1="15.3" x2="21" y2="21"></line><line x1="8" y1="9" x2="13" y2="9"></line><line x1="8" y1="12" x2="11.5" y2="12"></line></svg></span> <b>CodeRabbit / Greptile</b> <span class="ad-head-k">READS CODE</span> </div> <div class="ad-verdict">Code review is a different layer. Keep it.</div> <div class="ad-cols"> <div class="ad-col keep"><span class="ad-lbl">Keep it for</span><p>Catching real issues in the code itself, on every PR. We recommend running one.</p></div> <div class="ad-col stop"><span class="ad-lbl">Where it stops</span><p>A clean diff can still break the running product. Rendering, state, and flow bugs only exist at runtime, where a code reader can't see them.</p></div> </div> <div class="receipt"><span class="rc-ok">✓ LGTM. clean diff</span><span class="rc-bad">✕ /checkout 500s at runtime</span></div> <div class="ad-pie"><span class="ad-lbl">With Pie</span><p>They read your code. Pie uses your product. The two layers catch different bugs, and teams run both.</p></div> </div> </div> <div class="avi" role="tab" tabindex="0" aria-selected="false"> <span class="rt-chip"><svg class="rt-glyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 12a8 8 0 1 1-2.34-5.66"></path><polyline points="20 3 20 7 16 7"></polyline><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"></circle></svg></span> <div class="rt-tx"> <span class="lyr-k">TESTS ITSELF</span> <b>Claude Code testing itself</b> <span class="lyr-d">The author of the code grading its own homework.</span> </div> <div class="alt-detail"> <div class="ad-head"> <span class="ad-head-glyph"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 12a8 8 0 1 1-2.34-5.66"></path><polyline points="20 3 20 7 16 7"></polyline><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"></circle></svg></span> <b>Claude Code testing itself</b> <span class="ad-head-k">TESTS ITSELF</span> </div> <div class="ad-verdict">It can test your app once. Maybe.</div> <div class="ad-cols"> <div class="ad-col keep"><span class="ad-lbl">Keep it for</span><p>Quick sanity checks while you build. Genuinely useful at development time.</p></div> <div class="ad-col stop"><span class="ad-lbl">Where it stops</span><p>Not repeatable, not independent, and no memory of your product across releases. Verification can't come from the thing being verified.</p></div> </div> <div class="receipt"><span class="rc-ok">✓ tested my changes, all good!</span><span class="rc-bad">✕ same bug, third release running</span></div> <div class="ad-pie"><span class="ad-lbl">With Pie</span><p>The independent check with eyes: it runs the real UI on every push, and remembers how your product is supposed to behave.</p></div> </div> </div> <div class="avi" role="tab" tabindex="0" aria-selected="false"> <span class="rt-chip"><svg class="rt-glyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 13a8 8 0 0 1 16 0"></path><rect x="3" y="13" width="4" height="6" rx="1.6"></rect><rect x="17" y="13" width="4" height="6" rx="1.6"></rect><path d="M20 19a3 3 0 0 1-3 3h-3"></path></svg></span> <div class="rt-tx"> <span class="lyr-k">HUMANS + QUEUE</span> <b>Outsourced / managed QA</b> <span class="lyr-d">Humans writing scripts, with a handoff in the middle.</span> </div> <div class="alt-detail"> <div class="ad-head"> <span class="ad-head-glyph"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 13a8 8 0 0 1 16 0"></path><rect x="3" y="13" width="4" height="6" rx="1.6"></rect><rect x="17" y="13" width="4" height="6" rx="1.6"></rect><path d="M20 19a3 3 0 0 1-3 3h-3"></path></svg></span> <b>Outsourced / managed QA</b> <span class="ad-head-k">HUMANS + QUEUE</span> </div> <div class="ad-verdict">Managed QA is still scripts, plus a queue.</div> <div class="ad-cols"> <div class="ad-col keep"><span class="ad-lbl">Keep it for</span><p>Exploratory testing sprints and compliance sign-off still benefit from a human team.</p></div> <div class="ad-col stop"><span class="ad-lbl">Where it stops</span><p>Months to ramp, coverage that decays as the product moves, and every release waiting on someone else's schedule.</p></div> </div> <div class="receipt"><span class="rc-ok">✓ regression pass scheduled</span><span class="rc-bad">✕ ETA next Thursday</span></div> <div class="ad-pie"><span class="ad-lbl">With Pie</span><p>Coverage from day one that never goes stale. Pie tests every change the moment it ships, and a human reviews only what needs a human.</p></div> </div> </div> </div> <div class="alt-panel" id="altPanel" role="tabpanel"></div> </div> <a class="alt-more" href="/comparisons/">See every comparison <span class="ar">→</span></a> </div></section> <!-- WHO --><section class="who2" style="padding:110px 0 36px"><div class="wrap"> <h2>Built for teams shipping faster than their quality process can keep up.</h2> <p>If you've got a fully-staffed quality team that loves maintaining Playwright, you probably don't need us.</p> </div></section> <section id="faq" style="padding:56px 0 110px"><div class="wrap"><div class="faq-shell"><div class="faq-grid"> <div class="faq-left"> <h2 class="disp">FAQ</h2> <p>Did we miss a question?<br><a class="mail" href="/cdn-cgi/l/email-protection#3d55585151527d4d54581354535e">Email us directly →</a></p> </div> <div class="faq-right"> <div class="frow" tabindex="0"> <div class="fq">Won&#39;t this bury my team in false positives?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">No. Every finding is reproduced and reviewed before it reaches you. You see a short list of real, user-visible bugs, not a pile to triage. The bar we use: if a real user saw this, would they think something's wrong?</div> </div><div class="frow" tabindex="0"> <div class="fq">Is it safe to let Pie open PRs?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">Pie never merges anything. It opens a fix as a normal PR with the evidence attached (screenshots, the failing flow, the reasoning) and your team reviews it like any other contribution. Comment-only mode is available too.</div> </div><div class="frow" tabindex="0"> <div class="fq">What do we have to set up?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">Connect your repo and point Pie at your app. It maps your product on day one. No test scripts to write, no selectors to tag, nothing to maintain as your UI changes.</div> </div><div class="frow" tabindex="0"> <div class="fq">Do you support mobile?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">Yes. Web and native mobile (iOS and Android), including the flows scripts struggle to reach. Pie tests visually, so it works the same way everywhere your users do.</div> </div><div class="frow" tabindex="0"> <div class="fq">Is my code and data secure?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">Pie is SOC 2 Type 2 compliant. Access is scoped to what testing requires, and we're happy to walk your security team through the details. It's usually a 15-minute call.</div> </div><div class="frow" tabindex="0"> <div class="fq">What does it cost?</div> <button class="plus" aria-label="toggle">+</button> <div class="fa">Less than a QA hire, and it covers more than several. Pricing scales with your product, not per test. We'll show you exactly what it looks like for your team after a scan of your app.</div> </div> </div> </div></div></div></section> <!-- CTA (whisper of ripple) --><section class="closing"> <svg class="rip" viewBox="0 0 1440 560" preserveAspectRatio="xMidYMid slice"></svg> <div class="wrap"> <h2>See what Pie finds in your product.</h2> <p>Point us at your app. We'll show you the bugs before your users do.</p> <a class="btn p" style="font-size:15px;padding:15px 27px" href="https://app.pie.inc/start">See what Pie finds in your app →</a> </div> </section>  <footer class="big-footer" id="playground"> <canvas id="sandbox" aria-hidden="true"></canvas> <nav class="fwrap" aria-label="Footer"> <div class="fbrand"> <img src="/redesign/pie-logo-clean.svg" alt="pie" style="height:26px"> <p>Agentic testing for web &amp; mobile.<br>Ship the feature. Not the bug.</p> <a class="fsoc" href="/product/security/" aria-label="SOC 2 Type 2 certified. Read about security at Pie."> <svg width="12" height="13" viewBox="0 0 12 13" fill="none" aria-hidden="true"><path d="M6 .8 11 2.6v3.5c0 3-2.1 5.2-5 6.1C3.1 11.3 1 9.1 1 6.1V2.6L6 .8Z" fill="#e2f4ec" stroke="#17A673" stroke-width="1"></path><path d="M3.9 6.3l1.5 1.5 2.7-3" stroke="#17A673" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path></svg>
SOC 2 TYPE 2
</a> </div> <div class="fcol"><b>Product</b><a href="/product/how-it-works/">How it works</a><a href="/comparisons/">Comparisons</a><a href="/product/security/">Security</a><a href="/product/integrations/">Integrations</a></div> <div class="fcol"><b>Company</b><a href="/customers/">Customers</a><a href="/blog/">Blog</a><a href="/cdn-cgi/l/email-protection#d6beb3babab996a6bfb3f8bfb8b5">Contact</a></div> <div class="fcol"><b>Resources</b><a href="https://docs.pie.inc/">Docs</a><a href="/resources/whitepapers/">Whitepapers</a><a href="/privacy-policy/">Privacy</a></div> </nav> <div class="fbase"><span>© 2026 Pie Labs</span><a href="/privacy-policy/">Privacy</a><span class="playhint" aria-hidden="true">✦ go ahead, click around</span></div> </footer> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script src="/redesign/main.js" defer></script>  </body></html>