<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://docs.innerworks.me/whats-new</id>
    <title>Innerworks - What's New?</title>
    <updated>2026-07-13T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://docs.innerworks.me/whats-new"/>
    <subtitle>New features and changes to the Innerworks platform</subtitle>
    <icon>https://docs.innerworks.me/img/favicon.png</icon>
    <entry>
        <title type="html"><![CDATA[New docs with new branding!]]></title>
        <id>https://docs.innerworks.me/whats-new/2026/07/13/new-docs-with-new-branding</id>
        <link href="https://docs.innerworks.me/whats-new/2026/07/13/new-docs-with-new-branding"/>
        <updated>2026-07-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Innerworks documentation updated with new Innerworks branding.]]></summary>
        <content type="html"><![CDATA[<p>To tie into <a href="https://innerworks.me/" target="_blank" rel="noopener noreferrer" class="">the new website</a>, we have updated the documentation to match. Along with a more modern style.</p>
<p><strong>Before:</strong>
<img decoding="async" loading="lazy" alt="Old docs" src="https://docs.innerworks.me/assets/images/2026-07-13-old-docs-dcb1fe222ea9f4db2db5a045f8b6ebea.png" width="2384" height="1902" class="img_B8pD"></p>
<p><strong>After:</strong>
<img decoding="async" loading="lazy" alt="New docs" src="https://docs.innerworks.me/assets/images/2026-07-13-new-docs-dark-cf1ee090168b38029943c3d3a3735b12.png" width="2404" height="1420" class="img_B8pD"></p>
<p>Find the new documentation at <a href="https://docs.innerworks.me/" target="_blank" rel="noopener noreferrer" class="">https://docs.innerworks.me</a>.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dashboard loads 2-3x quicker]]></title>
        <id>https://docs.innerworks.me/whats-new/2026/07/10/dashboard-improvements</id>
        <link href="https://docs.innerworks.me/whats-new/2026/07/10/dashboard-improvements"/>
        <updated>2026-07-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Aggregating stats brings significant performance improvement.]]></summary>
        <content type="html"><![CDATA[<p>The main dashboard has historically been very slow to load, often taking nearly 15 seconds and sometimes timing out.</p>
<p>By aggregating stats earlier, the dashboard now loads 2-3x faster, and will not be significantly impacted by more data.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-label="Dashboard endpoint response times before and after pre-aggregating statistics. Every endpoint got faster; the biggest win was vpn-detection-stats at 6.5 times." class="viz-chart" style="font-family:Telegraf,system-ui,sans-serif" viewBox="0 0 996 456"><style>@media (prefers-color-scheme:light),(prefers-color-scheme:no-preference){.viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}}@media (prefers-color-scheme:dark){:root:where(:not([data-theme=light])) .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}}:root[data-theme=light] .viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}:root[data-theme=dark] .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}.viz-chart .viz-bar.viz-s1{fill:var(--s1,#008d80)}.viz-chart .viz-bar.viz-s2{fill:var(--s2,#c94f1c)}.viz-chart .viz-grid{stroke:var(--grid,#ddd4cf);stroke-width:1px}.viz-chart .viz-serieslabel{fill:var(--text,#221f1d);font-size:19px}.viz-chart .viz-mono{font-family:Geist Mono,SFMono-Regular,Menlo,monospace;font-size:17px}.viz-chart .viz-legendlabel{fill:var(--text,#221f1d);font-size:18px}.viz-chart .viz-value{fill:var(--muted,#6b6461);font-variant-numeric:tabular-nums;font-size:17px}.viz-chart .viz-speedup{fill:var(--text,#221f1d);font-variant-numeric:tabular-nums;font-size:18px;font-weight:800}.viz-chart .viz-tick{fill:var(--muted,#6b6461);font-size:17px}</style><path fill="var(--surface, #f9f4f1)" d="M0 0h996v456H0z"></path><g transform="translate(28 28)"><rect width="18" height="16" y="6" class="viz-bar viz-s2" rx="3"></rect><text x="28" y="14" class="viz-legendlabel" dominant-baseline="central">Raw stats</text><rect width="18" height="16" x="150" y="6" class="viz-bar viz-s1" rx="3"></rect><text x="178" y="14" class="viz-legendlabel" dominant-baseline="central">Aggregated stats</text></g><path d="M298 64v298M413 64v298M528 64v298M643 64v298M758 64v298" class="viz-grid"></path><path d="M270 334h460" style="stroke:var(--grid, #ddd4cf);stroke-width:1" transform="translate(28 28)"></path><text x="270" y="360" class="viz-tick" text-anchor="middle" transform="translate(28 28)">0s</text><text x="385" y="360" class="viz-tick" text-anchor="middle" transform="translate(28 28)">4s</text><text x="500" y="360" class="viz-tick" text-anchor="middle" transform="translate(28 28)">8s</text><text x="615" y="360" class="viz-tick" text-anchor="middle" transform="translate(28 28)">12s</text><text x="730" y="360" class="viz-tick" text-anchor="middle" transform="translate(28 28)">16s</text><text x="500" y="388" style="fill:var(--muted, #6b6461);font-size:17px" text-anchor="middle" transform="translate(28 28)">Response time</text><g transform="translate(28 28)"><title>account-clusters: 14.56s raw, 5.33s aggregated — 2.7× faster</title><text x="252" y="68" class="viz-serieslabel viz-mono" dominant-baseline="central" text-anchor="end">account-clusters</text><path d="M270 52h414.6q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s2"></path><text x="698.6" y="59.5" class="viz-value" dominant-baseline="central">14.56s</text><path d="M270 69h149.2q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s1"></path><text x="433.2" y="76.5" class="viz-value" dominant-baseline="central">5.33s</text><text x="940" y="68" class="viz-speedup" dominant-baseline="central" text-anchor="end">2.7× faster</text></g><g transform="translate(28 28)"><title>country-stats: 11.84s raw, 3.95s aggregated — 3.0× faster</title><text x="252" y="128" class="viz-serieslabel viz-mono" dominant-baseline="central" text-anchor="end">country-stats</text><path d="M270 112h336.4q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s2"></path><text x="620.4" y="119.5" class="viz-value" dominant-baseline="central">11.84s</text><path d="M270 129h109.6q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s1"></path><text x="393.6" y="136.5" class="viz-value" dominant-baseline="central">3.95s</text><text x="940" y="128" class="viz-speedup" dominant-baseline="central" text-anchor="end">3.0× faster</text></g><g transform="translate(28 28)"><title>vpn-detection-stats: 10.21s raw, 1.56s aggregated — 6.5× faster</title><text x="252" y="188" class="viz-serieslabel viz-mono" dominant-baseline="central" text-anchor="end">vpn-detection-stats</text><path d="M270 172h289.5q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s2"></path><text x="573.5" y="179.5" class="viz-value" dominant-baseline="central">10.21s</text><path d="M270 189h40.9q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s1"></path><text x="324.9" y="196.5" class="viz-value" dominant-baseline="central">1.56s</text><text x="940" y="188" class="viz-speedup" dominant-baseline="central" text-anchor="end">6.5× faster</text></g><g transform="translate(28 28)"><title>daily-stats: 8.31s raw, 3.86s aggregated — 2.2× faster</title><text x="252" y="248" class="viz-serieslabel viz-mono" dominant-baseline="central" text-anchor="end">daily-stats</text><path d="M270 232h234.9q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s2"></path><text x="518.9" y="239.5" class="viz-value" dominant-baseline="central">8.31s</text><path d="M270 249h107q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s1"></path><text x="391" y="256.5" class="viz-value" dominant-baseline="central">3.86s</text><text x="940" y="248" class="viz-speedup" dominant-baseline="central" text-anchor="end">2.2× faster</text></g><g transform="translate(28 28)"><title>active-accounts: 7.65s raw, 3.74s aggregated — 2.0× faster</title><text x="252" y="308" class="viz-serieslabel viz-mono" dominant-baseline="central" text-anchor="end">active-accounts</text><path d="M270 292h215.9q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s2"></path><text x="499.9" y="299.5" class="viz-value" dominant-baseline="central">7.65s</text><path d="M270 309h103.5q4 0 4 4v7q0 4-4 4H270Z" class="viz-bar viz-s1"></path><text x="387.5" y="316.5" class="viz-value" dominant-baseline="central">3.74s</text><text x="940" y="308" class="viz-speedup" dominant-baseline="central" text-anchor="end">2.0× faster</text></g></svg>
<p><em>The page as a whole is gated by its slowest query, which is why the headline is 2-3x rather than the 6.5x that VPN detection stats managed on its own.</em></p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Sign in with Microsoft]]></title>
        <id>https://docs.innerworks.me/whats-new/2026/06/24/sign-in-with-microsoft</id>
        <link href="https://docs.innerworks.me/whats-new/2026/06/24/sign-in-with-microsoft"/>
        <updated>2026-06-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[You can now sign in to the Innerworks portal with a Microsoft 365 account.]]></summary>
        <content type="html"><![CDATA[<p>If your organisation runs on Microsoft 365, you no longer need a separate Google account to get into the portal.</p>
<p>There is now a <strong>Sign in with Microsoft</strong> button on the login screen, sitting alongside the existing Google option. Both work the same way, and you can mix and match across your team.</p>
<p><img decoding="async" loading="lazy" alt="Sign in with Microsoft" src="https://docs.innerworks.me/assets/images/2026-06-24-microsoft-signin-b1a706e3dcbaf0ccb0d45a796d643a63.png" width="818" height="676" class="img_B8pD"></p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Unified Detection]]></title>
        <id>https://docs.innerworks.me/whats-new/2026/02/24/unified-detection</id>
        <link href="https://docs.innerworks.me/whats-new/2026/02/24/unified-detection"/>
        <updated>2026-02-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[One endpoint runs the whole pipeline, so shared analysis happens once instead of once per detection type.]]></summary>
        <content type="html"><![CDATA[<p>Detection types used to live behind separate endpoints, and each of them redid a lot of the same underlying analysis. If you wanted fingerprinting and VPN status, you paid for that work twice.</p>
<p>There is now a single endpoint that runs the whole pipeline. The shared analysis happens once and every detection type builds on it, so asking for several of them together is considerably faster than asking for them one at a time.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-label="The inference pipeline drawn as a dependency graph. A request feeds three shared stages: historical data, the hard fingerprint and VPN detection. Between them these feed every other stage and all four results returned in the response, and none is computed more than once per request." class="viz-chart" style="font-family:Telegraf,system-ui,sans-serif" viewBox="0 0 996 407"><style>@media (prefers-color-scheme:light),(prefers-color-scheme:no-preference){.viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}}@media (prefers-color-scheme:dark){:root:where(:not([data-theme=light])) .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}}:root[data-theme=light] .viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}:root[data-theme=dark] .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}.viz-chart .dag-box{fill:var(--surface,#f9f4f1);stroke:var(--grid,#ddd4cf);stroke-width:2px}.viz-chart .dag-label{fill:var(--text,#221f1d);font-size:17px}.viz-chart .dag-edge{fill:none;stroke:var(--grid,#ddd4cf);stroke-width:2px}.viz-chart .dag-opt{stroke-dasharray:5 5}.viz-chart .dag-shared .dag-box{stroke:var(--s1,#008d80);stroke-width:3px}.viz-chart .dag-out .dag-box{stroke:var(--s2,#c94f1c)}.viz-chart .dag-from-shared{stroke:var(--s1,#008d80);opacity:.55}.viz-chart .dag-legend{fill:var(--text,#221f1d);font-size:17px}</style><path fill="var(--surface, #f9f4f1)" d="M0 0h996v407H0z"></path><g class="dag-legendrow"><g class="dag-shared" transform="translate(28 28)"><rect width="26" height="17" y="6" class="dag-box" rx="4"></rect><text x="36" y="15" class="dag-legend" dominant-baseline="central">Computed once, reused</text></g><g class="dag-mid" transform="translate(28 28)"><rect width="26" height="17" x="280" y="6" class="dag-box" rx="4"></rect><text x="316" y="15" class="dag-legend" dominant-baseline="central">Intermediate stage</text></g><g class="dag-out" transform="translate(28 28)"><rect width="26" height="17" x="520" y="6" class="dag-box" rx="4"></rect><text x="556" y="15" class="dag-legend" dominant-baseline="central">Returned to you</text></g><text x="940" y="15" dominant-baseline="central" style="fill:var(--muted, #6b6461);font-size:16px" text-anchor="end" transform="translate(28 28)">dashed = optional</text></g><path d="M132 200c46 0 46-93 92-93M132 200h92M132 200c46 0 46 93 92 93" class="dag-edge dag-from-req"></path><path d="M132 200c30 0 32-99 62-99h578" class="dag-edge dag-from-req"></path><path d="M392 107c30 0 32 6 62 6h318" class="dag-edge dag-from-shared"></path><path d="M392 107c30 0 32 68 62 68h318" class="dag-edge dag-from-shared"></path><path d="M392 107c30 0 32 132 62 132h318" class="dag-edge dag-from-shared"></path><path d="M392 107c30 0 32 192 62 192h318" class="dag-edge dag-from-shared"></path><path d="M392 200c46 0 46-62 92-62M392 200h92M392 200c46 0 46 124 92 124" class="dag-edge dag-from-shared"></path><path d="M392 200c30 0 32-37 62-37h318M392 200c30 0 32 23 62 23h318M392 293c46 0 46-31 92-31" class="dag-edge dag-from-shared"></path><path d="M392 293c30 0 32-62 62-62h318" class="dag-edge dag-from-shared"></path><path d="M392 293c30 0 32-6 62-6h318" class="dag-edge dag-from-shared"></path><path d="M664 138c54 0 54 31 108 31" class="dag-edge dag-from-mid dag-opt"></path><path d="M664 200c54 0 54 31 108 31" class="dag-edge dag-from-mid"></path><path d="M664 200c54 0 54 93 108 93" class="dag-edge dag-from-mid"></path><path d="M664 262c54 0 54 31 108 31M664 324c54 0 54-31 108-31" class="dag-edge dag-from-mid dag-opt"></path><g class="dag-req" transform="translate(28 28)"><title>Request — InferencePipelineInput</title><rect width="104" height="42" y="151" class="dag-box" rx="7"></rect><text x="52" y="172" class="dag-label" dominant-baseline="central" text-anchor="middle">Request</text></g><g class="dag-shared" transform="translate(28 28)"><title>Historical data — historical</title><rect width="168" height="42" x="196" y="58" class="dag-box" rx="7"></rect><text x="280" y="79" class="dag-label" dominant-baseline="central" text-anchor="middle">Historical data</text></g><g class="dag-shared" transform="translate(28 28)"><title>Hard fingerprint — fingerprint:hard</title><rect width="168" height="42" x="196" y="151" class="dag-box" rx="7"></rect><text x="280" y="172" class="dag-label" dominant-baseline="central" text-anchor="middle">Hard fingerprint</text></g><g class="dag-shared" transform="translate(28 28)"><title>VPN detection — geolocation:vpndetectionresult</title><rect width="168" height="42" x="196" y="244" class="dag-box" rx="7"></rect><text x="280" y="265" class="dag-label" dominant-baseline="central" text-anchor="middle">VPN detection</text></g><g class="dag-mid" transform="translate(28 28)"><title>Soft fingerprint — fingerprint:soft</title><rect width="180" height="42" x="456" y="89" class="dag-box" rx="7"></rect><text x="546" y="110" class="dag-label" dominant-baseline="central" text-anchor="middle">Soft fingerprint</text></g><g class="dag-mid" transform="translate(28 28)"><title>Location history — geolocation:historicalnonvpnlocation</title><rect width="180" height="42" x="456" y="151" class="dag-box" rx="7"></rect><text x="546" y="172" class="dag-label" dominant-baseline="central" text-anchor="middle">Location history</text></g><g class="dag-mid" transform="translate(28 28)"><title>Geolocation (exp.) — experimental:geolocation</title><rect width="180" height="42" x="456" y="213" class="dag-box" rx="7"></rect><text x="546" y="234" class="dag-label" dominant-baseline="central" text-anchor="middle">Geolocation (exp.)</text></g><g class="dag-mid" transform="translate(28 28)"><title>Fingerprint (exp.) — experimental:fingerprint</title><rect width="180" height="42" x="456" y="275" class="dag-box" rx="7"></rect><text x="546" y="296" class="dag-label" dominant-baseline="central" text-anchor="middle">Fingerprint (exp.)</text></g><g class="dag-out" transform="translate(28 28)"><title>Bot detection — botdetection</title><rect width="196" height="42" x="744" y="58" class="dag-box" rx="7"></rect><text x="842" y="79" class="dag-label" dominant-baseline="central" text-anchor="middle">Bot detection</text></g><g class="dag-out" transform="translate(28 28)"><title>Fingerprint — fingerprint</title><rect width="196" height="42" x="744" y="120" class="dag-box" rx="7"></rect><text x="842" y="141" class="dag-label" dominant-baseline="central" text-anchor="middle">Fingerprint</text></g><g class="dag-out" transform="translate(28 28)"><title>Geolocation — geolocation</title><rect width="196" height="42" x="744" y="182" class="dag-box" rx="7"></rect><text x="842" y="203" class="dag-label" dominant-baseline="central" text-anchor="middle">Geolocation</text></g><g class="dag-out" transform="translate(28 28)"><title>Experimental — experimental</title><rect width="196" height="42" x="744" y="244" class="dag-box" rx="7"></rect><text x="842" y="265" class="dag-label" dominant-baseline="central" text-anchor="middle">Experimental</text></g></svg>
<p>Historical data, the hard fingerprint and the VPN lookup are the three stages everything else is built on. Each is computed once per request, no matter how many results you ask for.</p>
<p>With one pipeline rather than a set of parallel ones, we can also add new detection types and iterate on the algorithms behind the existing ones much faster - and those improvements or access to beta versions reach you with minimal change.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[The SDK now updates itself]]></title>
        <id>https://docs.innerworks.me/whats-new/2026/02/19/the-sdk-now-updates-itself</id>
        <link href="https://docs.innerworks.me/whats-new/2026/02/19/the-sdk-now-updates-itself"/>
        <updated>2026-02-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[v2.0.0 of the JavaScript SDK loads its detection core at runtime, so you get new signals without shipping a release.]]></summary>
        <content type="html"><![CDATA[<p>Version 2.0.0 of the JavaScript SDK is out, and it works a little differently.</p>
<p>The npm package is now a thin client. When it initialises, it fetches its detection core from our CDN at runtime. The upshot is that new signals and detection improvements reach your users automatically, without you needing to bump a dependency and redeploy.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-label="How version 2 of the SDK updates itself. Innerworks publishes sdk-core to its CDN. On your site, your app calls the pinned iw-auth-sdk npm package, which fetches the detection core from that CDN at runtime. Only the thin client is pinned by you; the core it loads is always current." class="viz-chart" style="font-family:Telegraf,system-ui,sans-serif" viewBox="0 0 876 428"><style>@media (prefers-color-scheme:light),(prefers-color-scheme:no-preference){.viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}}@media (prefers-color-scheme:dark){:root:where(:not([data-theme=light])) .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}}:root[data-theme=light] .viz-chart{--surface:#f9f4f1;--text:#221f1d;--muted:#6b6461;--grid:#ddd4cf;--s1:#008d80;--s2:#c94f1c}:root[data-theme=dark] .viz-chart{--surface:#0b0a0a;--text:#f9f4f1;--muted:#9a938f;--grid:#2c2927;--s1:#00a99b;--s2:#e0652f}.viz-chart .arch-box{fill:var(--surface,#f9f4f1);stroke:var(--grid,#ddd4cf);stroke-width:2px}.viz-chart .arch-auto .arch-box{stroke:var(--s1,#008d80);stroke-width:3px}.viz-chart .arch-edge{fill:none;stroke:var(--grid,#ddd4cf);stroke-width:2px}.viz-chart .arch-head{fill:var(--grid,#ddd4cf);stroke:none}.viz-chart .arch-edge.is-auto{stroke:var(--s1,#008d80)}.viz-chart .arch-head.is-auto{fill:var(--s1,#008d80)}.viz-chart .arch-zone{fill:none;stroke:var(--grid,#ddd4cf);stroke-width:2px;stroke-dasharray:7 6}.viz-chart .arch-label{fill:var(--text,#221f1d);font-size:19px}.viz-chart .arch-sub{fill:var(--muted,#6b6461);font-size:15px}.viz-chart .arch-note,.viz-chart .arch-zonelabel{fill:var(--muted,#6b6461);font-size:17px}.viz-chart .arch-note{font-size:16px}</style><path fill="var(--surface, #f9f4f1)" d="M0 0h876v428H0z"></path><g transform="translate(28 28)"><g class="arch-fixed"><rect width="26" height="17" y="6" class="arch-box" rx="4"></rect><text x="36" y="15" class="arch-label" dominant-baseline="central">Pinned by you</text></g><g class="arch-auto"><rect width="26" height="17" x="210" y="6" class="arch-box" rx="4"></rect><text x="246" y="15" class="arch-label" dominant-baseline="central">Updates automatically</text></g><rect width="520" height="138" x="280" y="42" class="arch-zone" rx="14"></rect><text x="300" y="64" class="arch-zonelabel">Innerworks</text><rect width="820" height="138" y="232" class="arch-zone" rx="14"></rect><text x="20" y="254" class="arch-zonelabel">Your site</text><path d="M510 111h41" class="arch-edge is-auto"></path><path d="m560 111-9-5v10Z" class="arch-head is-auto"></path><path d="M175 301h31" class="arch-edge"></path><path d="m215 301-9-5v10Z" class="arch-head"></path><path d="M450 301h101" class="arch-edge is-auto"></path><path d="m560 301-9-5v10Z" class="arch-head is-auto"></path><path d="M680 140v123" class="arch-edge is-auto"></path><path d="m680 272-5-9h10Z" class="arch-head is-auto"></path><text x="662" y="215" class="arch-note" dominant-baseline="central" text-anchor="end">fetched at runtime</text><text x="505" y="283" class="arch-note" dominant-baseline="central" text-anchor="middle">loads</text><g class="arch-auto"><rect width="200" height="58" x="310" y="82" class="arch-box" rx="7"></rect><text x="410" y="104" class="arch-label" dominant-baseline="central" text-anchor="middle">sdk-core</text><text x="410" y="124" class="arch-sub" dominant-baseline="central" text-anchor="middle">new signals land here</text></g><g class="arch-auto"><rect width="240" height="58" x="560" y="82" class="arch-box" rx="7"></rect><text x="680" y="104" class="arch-label" dominant-baseline="central" text-anchor="middle">Innerworks CDN</text><text x="680" y="124" class="arch-sub" dominant-baseline="central" style="font-family:&amp;quot;font-size:14px" text-anchor="middle">sdk-cdn.prod.innerworks.me</text></g><g class="arch-fixed"><rect width="155" height="58" x="20" y="272" class="arch-box" rx="7"></rect><text x="97.5" y="301" class="arch-label" dominant-baseline="central" text-anchor="middle">Your app</text></g><g class="arch-fixed"><rect width="235" height="58" x="215" y="272" class="arch-box" rx="7"></rect><text x="332.5" y="294" class="arch-label" dominant-baseline="central" text-anchor="middle">iw-auth-sdk</text><text x="332.5" y="314" class="arch-sub" dominant-baseline="central" text-anchor="middle">pinned in package.json</text></g><g class="arch-auto"><rect width="240" height="58" x="560" y="272" class="arch-box" rx="7"></rect><text x="680" y="294" class="arch-label" dominant-baseline="central" text-anchor="middle">Detection core</text><text x="680" y="314" class="arch-sub" dominant-baseline="central" text-anchor="middle">collectors, transport</text></g></g></svg>
<p>The version you pin in <code>package.json</code> is the thin client. The detection core it pulls in is whatever we have published, so improvements land without a release on your side.</p>
<div class="theme-admonition theme-admonition-important admonition_dBf_ alert alert--info"><div class="admonitionHeading_v2Rc"><span class="admonitionIcon_cQIP"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>important</div><div class="admonitionContent_ZEVI"><p><strong>One thing you need to do:</strong> if your site sets a Content Security Policy, allowlist <code>sdk-cdn.prod.innerworks.me</code> under <code>script-src</code> (or <code>default-src</code>).</p><p>Without it the core cannot load. See <a class="" href="https://docs.innerworks.me/docs/getting-started/quickstart">the quickstart</a> for the details.</p></div></div>
<p>A couple of other changes worth knowing about while you are upgrading:</p>
<ul>
<li class=""><code>send()</code> is deprecated in favour of <code>sendMetrics()</code>. The old name still works and just forwards on.</li>
<li class=""><code>detectionResult</code> on the response has been replaced by <code>detectionResultJwt</code>.</li>
<li class=""><code>detectionTypes</code> is no longer a config option. Which detections run is now driven by your project configuration, so you can change it without a code change.</li>
</ul>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Introducing the dashboard]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/11/05/a-new-look-for-the-dashboard</id>
        <link href="https://docs.innerworks.me/whats-new/2025/11/05/a-new-look-for-the-dashboard"/>
        <updated>2025-11-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A live view of your detection data, with a threat map, account clusters and filtering across every project.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" src="https://docs.innerworks.me/assets/images/2025-11-05-dashboard-revamp-dark-94e439f5f2043f6c423a06566048885d.png" width="2912" height="2654" class="img_B8pD"></p>
<p>Until now, the only way to see what Innerworks was detecting was to query the API yourself. There is now a dashboard.</p>
<p>At the top are the numbers you probably care about most: total requests, active accounts, VPN detections and high-risk countries. Below that is a threat map that highlights where your traffic is coming from and flags VPN-originating sessions, and you can click a country on the map to filter everything else on the page down to it.</p>
<p>There is also an account clusters section, which surfaces groups of accounts that look linked by shared device or location activity.</p>
<p>You can narrow the whole dashboard by project, country, fingerprint and a date and time range, and your selections stay put as you move between sections. Every metric card carries a tooltip explaining exactly what it is counting.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Try it in the playground]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/08/29/try-it-in-the-playground</id>
        <link href="https://docs.innerworks.me/whats-new/2025/08/29/try-it-in-the-playground"/>
        <updated>2025-08-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Run detection against your own browser from inside the portal, with no integration.]]></summary>
        <content type="html"><![CDATA[<p>There is now a playground in the portal that runs the SDK against the browser you are sitting in front of.</p>
<p>It returns what your integration would return: the device fingerprint, VPN status and true geolocation, the detected OS and browser, the IP addresses we saw, and the decoded token. No project setup, no code.</p>
<p>It is the quickest way to see what a detection result actually looks like before you wire anything up, and a useful sanity check afterwards when you want to confirm a signal is behaving the way you expect.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[A real response from the SDK]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/03/25/a-real-response-from-sendmetrics</id>
        <link href="https://docs.innerworks.me/whats-new/2025/03/25/a-real-response-from-sendmetrics"/>
        <updated>2025-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Sends now return a structured result with a request ID, instead of just true or false.]]></summary>
        <content type="html"><![CDATA[<p>Sending metrics used to give you back a boolean. If it returned <code>false</code> you knew something had gone wrong, and that was the end of what you could find out.</p>
<p>As of v1.7.2 you get a structured response instead: an overall result, a request ID, the detection result itself, and per-detection-type errors when something partially fails.</p>
<p>The request ID is the useful part. Quote it to us in a support conversation and we can find the exact request. Pass it to <a class="" href="https://docs.innerworks.me/docs/advanced/api-access">the results endpoint</a> and you can fetch the same detection result server-side, which is the recommended way to make a decision on it - a result read in the browser is a result an attacker can tamper with.</p>
<p>Partial results matter too. If you have asked for several detection types and one of them fails, you now get the ones that succeeded plus an error for the one that did not, rather than losing the whole response.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Fetch results from your own backend]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/03/20/fetch-results-from-your-own-backend</id>
        <link href="https://docs.innerworks.me/whats-new/2025/03/20/fetch-results-from-your-own-backend"/>
        <updated>2025-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Project API keys, and an endpoint that returns a detection result by request ID.]]></summary>
        <content type="html"><![CDATA[<p>Reading a detection result in the browser is convenient but easy to tamper with, and makes it easier for a malicious user to train against. You can now fetch the same result server-side instead.</p>
<p>Every project has an API key, which you can reveal and copy from the portal. Take the request ID the SDK hands back and ask for the result directly:</p>
<div class="language-bash codeBlockContainer_XRLj theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_PKA4"><pre tabindex="0" class="prism-code language-bash codeBlock_z9zc thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_P0zd"><div class="token-line" style="color:#393A34"><span class="token plain">curl --request GET \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference?request_id={REQUEST_ID}' \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --header 'x-api-key: {API_KEY}'</span><br></div></code></pre></div></div>
<p>The default response is the short version - the fingerprint, whether a VPN was in use, and the true location behind it. Pass <code>format=detailed</code> and you also get browser, OS, user ID, geolocation and the reasoning behind the detection.</p>
<p>This is the recommended way to act on a result. <a class="" href="https://docs.innerworks.me/docs/advanced/api-access">API access</a> covers both response formats in full.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Verify results on your backend]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/02/27/verify-results-on-your-backend</id>
        <link href="https://docs.innerworks.me/whats-new/2025/02/27/verify-results-on-your-backend"/>
        <updated>2025-02-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Detection results are signed, so you can prove a result came from us and has not been altered.]]></summary>
        <content type="html"><![CDATA[<p>A detection result that arrives through the browser has passed through a place you do not control. If you are going to block a signup or flag a session on the strength of it, you need to know it is the result we actually issued.</p>
<p>Results now come back as a signed JWT, and there is a JWKS endpoint you can verify it against:</p>
<div class="language-text codeBlockContainer_XRLj theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_PKA4"><pre tabindex="0" class="prism-code language-text codeBlock_z9zc thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_P0zd"><div class="token-line" style="color:#393A34"><span class="token plain">https://api.prod.innerworks.me/api/v1/.well-known/jwks.json</span><br></div></code></pre></div></div>
<p>Verify on your backend, not in the page - a check that runs in the browser can be skipped by anyone who controls the browser.</p>
<p><a class="" href="https://docs.innerworks.me/docs/advanced/jwt-verification">JWT verification</a> has a worked example.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Pure JavaScript integration]]></title>
        <id>https://docs.innerworks.me/whats-new/2025/01/19/integrate-without-npm</id>
        <link href="https://docs.innerworks.me/whats-new/2025/01/19/integrate-without-npm"/>
        <updated>2025-01-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Drop in a hidden iframe and start collecting, with no changes to your build.]]></summary>
        <content type="html"><![CDATA[<p>Not every team can add a dependency to their frontend. Some are on a platform that does not let them, some would rather not touch the build at all, and some just want to try Innerworks before committing to an integration.</p>
<p>There is now a hosted version of the SDK you can embed directly:</p>
<div class="language-html codeBlockContainer_XRLj theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_PKA4"><pre tabindex="0" class="prism-code language-html codeBlock_z9zc thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_P0zd"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">iframe</span><span class="token tag" style="color:#00009f"></span><br></div><div class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">  </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">innerworks_sdk</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"></span><br></div><div class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">  </span><span class="token tag attr-name" style="color:#00a4db">src</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">https://sdk.prod.innerworks.me?projectId=project_id</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"></span><br></div><div class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f">  </span><span class="token tag special-attr attr-name" style="color:#00a4db">style</span><span class="token tag special-attr attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag special-attr attr-value value css language-css property" style="color:#36acaa">display</span><span class="token tag special-attr attr-value value css language-css punctuation" style="color:#393A34">:</span><span class="token tag special-attr attr-value value css language-css" style="color:#e3116c"> none</span><span class="token tag special-attr attr-value value css language-css punctuation" style="color:#393A34">;</span><span class="token tag special-attr attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"></span><br></div><div class="token-line" style="color:#393A34"><span class="token tag" style="color:#00009f"></span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">iframe</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<p>Configuration goes in the query string and results come back by <code>postMessage</code>, so you can read them from the parent page. Everything the npm package collects, the hosted page collects too.</p>
<p><a class="" href="https://docs.innerworks.me/docs/advanced/iframe-integration">iFrame integration</a> has the full setup, including how to pass a social ID and how to handle the response.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Metrics payloads are now encrypted]]></title>
        <id>https://docs.innerworks.me/whats-new/2024/08/01/encrypted-metrics-payloads</id>
        <link href="https://docs.innerworks.me/whats-new/2024/08/01/encrypted-metrics-payloads"/>
        <updated>2024-08-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The SDK encrypts collected metrics with our public key before they leave the browser.]]></summary>
        <content type="html"><![CDATA[<p>Everything the SDK collects is now encrypted with the Innerworks public key before it is sent.</p>
<p>The signals we collect describe a device, not a person, but they still travel across a network you do not control, so they should not travel in the clear. This happens inside the SDK - there is nothing to configure and nothing to change in your integration.</p>
<p>This prevents anyone from seeing what data is collected on the browser and sent to innerworks.</p>]]></content>
    </entry>
</feed>