<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[FindIP Engineering]]></title><description><![CDATA[FindIP Engineering]]></description><link>https://findipnet.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6acddb28747221e5c6988825/3289989e-5ee5-4f7b-9174-991abc509d08.png</url><title>FindIP Engineering</title><link>https://findipnet.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 26 Oct 2026 18:40:29 GMT</lastBuildDate><atom:link href="https://findipnet.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Bots, VPNs and fake checkouts on Shopify: what you can see and what you can do]]></title><description><![CDATA[Spot bot, proxy and datacenter traffic on a Shopify store, and use Shopify's own tools to act on risky orders and junk traffic.]]></description><link>https://findipnet.hashnode.dev/bots-vpns-and-fake-checkouts-on-shopify-what-you-can-see-and-what-you-can-do</link><guid isPermaLink="true">https://findipnet.hashnode.dev/bots-vpns-and-fake-checkouts-on-shopify-what-you-can-see-and-what-you-can-do</guid><category><![CDATA[shopify]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[Security]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[FindIP]]></dc:creator><pubDate>Thu, 22 Oct 2026 15:44:49 GMT</pubDate><content:encoded><![CDATA[<p>If your Shopify analytics show a spike of sessions from a country you don't ship to, add-to-carts that never convert, or a burst of failed payments at 2 a.m., you're not imagining it. A share of every store's traffic comes from scrapers, price bots, card testers and people hiding behind proxies.</p>
<p>Shopify handles a lot of this for you. Some of it, it doesn't. Here's what you can see, and what you can actually do about it, mostly with tools you already have.</p>
<h2>1. What Shopify already does</h2>
<p>Before installing anything, know what's on by default:</p>
<ul>
<li><strong>Platform-level bot protection.</strong> Shopify sits behind Cloudflare and filters a lot of abusive traffic before it reaches your store.</li>
<li><strong>hCaptcha on forms.</strong> It's on by default for contact, comment, login and account-creation forms. Check it's still on under Online Store &gt; Preferences &gt; Spam protection.</li>
<li><strong>Checkout protection.</strong> Shopify runs its own checks on checkout. Extra bot protection during high-traffic sales is a Shopify Plus feature.</li>
<li><strong>Fraud analysis on orders.</strong> Eligible orders get a low, medium or high risk recommendation with indicators, and stores on Shopify Payments also get proxy detection. Shopify's own advice is to go by the recommendation, not by any single indicator such as the IP address.</li>
</ul>
<p>That covers a lot of card fraud. What it doesn't give you is a clear picture of your <strong>traffic</strong>: how much of it is people, and how much is automated or anonymized.</p>
<h2>2. Why the traffic picture matters</h2>
<p>Bot and proxy traffic on a store costs you in quieter ways than fraud:</p>
<ul>
<li><strong>Wrong numbers.</strong> Conversion rate, bounce rate and "sessions by country" all include traffic that was never going to buy.</li>
<li><strong>Wasted ad spend.</strong> Paid clicks from datacenter networks are rarely shoppers.</li>
<li><strong>Card testing.</strong> Waves of small payment attempts, often from rotating proxies, show up as failed payments before they show up as chargebacks.</li>
<li><strong>Scraping.</strong> Competitors and resellers pulling your catalog and prices.</li>
</ul>
<p>The tell is usually the <strong>network</strong> the traffic comes from. Shoppers browse from home broadband and mobile carriers. Bots and scrapers run on cloud servers (AWS, DigitalOcean, OVH, Hetzner) and route through proxies.</p>
<h2>3. What to look at</h2>
<p>Whatever tool you use, these are the questions that matter:</p>
<ul>
<li>What share of <strong>page views</strong> come from hosting or datacenter networks?</li>
<li>What share of <strong>checkouts started</strong> come from VPNs, proxies or Tor, and is that share higher than for page views?</li>
<li>Do <strong>payment attempts</strong> from risky networks cluster in bursts? That's what card testing looks like.</li>
<li>Do spikes in "sessions from country X" line up with a single hosting provider?</li>
</ul>
<p>You'll usually find a few clear patterns (a scraper on one cloud provider, a burst of proxy checkouts on one night) rather than a general problem. Shoppers on VPNs are mostly real people, so a VPN on its own tells you little.</p>
<h2>4. What you can do about it</h2>
<p>On Shopify, the store front is yours but checkout is Shopify's, so the levers are:</p>
<table>
<thead>
<tr>
<th>Problem</th>
<th>What works on Shopify</th>
</tr>
</thead>
<tbody><tr>
<td>Spam on contact and account forms</td>
<td>Keep hCaptcha on in spam protection settings</td>
</tr>
<tr>
<td>Risky orders</td>
<td>Read the order's fraud analysis, and use Shopify Flow to tag, hold or flag high-risk orders for review</td>
</tr>
<tr>
<td>Card-testing waves</td>
<td>Watch failed payments by network and time; Shopify's own checks and your payment provider's rules do the blocking</td>
</tr>
<tr>
<td>Scrapers and junk traffic in analytics</td>
<td>Identify the networks, then exclude or segment them in your analytics and ad reports</td>
</tr>
<tr>
<td>Blocking whole countries or VPN users on the storefront</td>
<td>Blocker apps can do it with a storefront script; test carefully, since real customers use VPNs and checkout itself stays Shopify's</td>
</tr>
</tbody></table>
<p>The general rule holds here too: look before you block. A storefront that blocks every VPN user turns away real customers and still can't touch what happens inside Shopify's checkout.</p>
<h2>Where FindIP Shield fits</h2>
<p>Disclosure: we make FindIP Shield, which does the "what to look at" part for free.</p>
<ul>
<li>It uses Shopify's Web Pixels API and reports <strong>page views, checkouts started and payment info submitted</strong>, each scored for VPN, proxy, Tor, hosting or datacenter network and known malicious IPs, with the reasons, in a dashboard.</li>
<li>It runs only when the shopper has given analytics consent, under Shopify's Customer Privacy controls.</li>
<li>It's deliberately minimal: no names, emails, addresses, customer or order IDs, cart contents, search queries or payment details are sent, and page URLs are stripped of query strings.</li>
<li>It reports; it doesn't block shoppers. Because it never sees order IDs, use Shopify's fraud analysis for individual orders and Shield for the traffic picture around them.</li>
<li>Free up to 10,000 events per site per day.</li>
</ul>
<p>It's on the Shopify App Store as <a href="https://apps.shopify.com/findip-shield">FindIP Shield</a>, and there's an <a href="https://www.findip.net/shield/demo">example dashboard with sample data</a> and a <a href="https://www.findip.net/shopify">Shopify overview</a> if you want to see what it shows first.</p>
<h2>The short version</h2>
<ol>
<li>Use what Shopify already gives you: hCaptcha on forms, fraud analysis on orders.</li>
<li>Find out which networks your traffic comes from: residential, hosting, VPN, Tor.</li>
<li>Look for patterns (one cloud provider, one burst of failed payments) before blocking anything.</li>
<li>Act with Shopify Flow on risky orders and segment junk traffic out of your numbers.</li>
<li>Don't block VPN shoppers outright. Most of them are customers.</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[How to detect VPN and proxy signups on WordPress (and what to do about them)]]></title><description><![CDATA[Spot fake registrations, spam leads and risky WooCommerce orders from VPNs, proxies and cloud servers without locking out real users.]]></description><link>https://findipnet.hashnode.dev/how-to-detect-vpn-and-proxy-signups-on-wordpress-and-what-to-do-about-them</link><guid isPermaLink="true">https://findipnet.hashnode.dev/how-to-detect-vpn-and-proxy-signups-on-wordpress-and-what-to-do-about-them</guid><category><![CDATA[WordPress]]></category><category><![CDATA[Security]]></category><category><![CDATA[webdev]]></category><category><![CDATA[woocommerce]]></category><dc:creator><![CDATA[FindIP]]></dc:creator><pubDate>Thu, 22 Oct 2026 15:32:13 GMT</pubDate><content:encoded><![CDATA[<p>If you run a WordPress site with open registration, a contact form or a WooCommerce checkout, you've seen it: a wave of new accounts with throwaway emails, contact-form spam at 3 a.m., orders that look fine until the chargeback arrives. A lot of that traffic doesn't come from home internet connections. It comes through VPNs, open proxies, Tor and rented cloud servers.</p>
<p>Detecting that is easy. Deciding what to do with it is where most setups go wrong: millions of legitimate people use a VPN every day, and a site that blocks all of them loses real customers.</p>
<p>Here's how to approach it on WordPress, in the order that keeps false positives low.</p>
<h2>1. Know which network your visitors come from</h2>
<p>Every request arrives from an IP address, and that address belongs to a network. The useful question isn't "which IP?" but "what kind of network?":</p>
<ul>
<li><strong>Residential or mobile ISP</strong>: home broadband, phone carriers. This is almost everyone.</li>
<li><strong>Hosting or datacenter</strong>: AWS, DigitalOcean, OVH, Hetzner and friends. Real people rarely browse from these; scripts and cheap proxies do.</li>
<li><strong>Commercial VPN, open proxy, Tor</strong>: anonymized traffic. Common for privacy-minded users, also common for abuse.</li>
<li><strong>Known malicious IPs</strong>: addresses already seen scanning, spamming or attacking.</li>
</ul>
<p>WordPress doesn't tell you any of this. You need an IP intelligence lookup: either a plugin that calls one, or a layer in front of the site (Cloudflare) that classifies traffic for you.</p>
<h2>2. Look before you block</h2>
<p>The most common mistake is installing a blocker, switching on "block all VPNs", and walking away. Two weeks later a customer emails to say they couldn't check out from their company laptop.</p>
<p>Run in monitor mode first, for a week if you can:</p>
<ul>
<li>What share of <strong>registrations</strong> come from hosting networks or VPNs?</li>
<li>What share of <strong>orders</strong>, and do those orders get refunded or charged back more?</li>
<li>Are your <strong>contact-form spam</strong> submissions concentrated on a few networks?</li>
</ul>
<p>You'll usually find that the abuse sits in a few clear patterns (datacenter IPs on the registration form, say), while VPN users on checkout are mostly fine. That tells you exactly where to add friction and where to leave things alone.</p>
<h2>3. Watch out for page caching</h2>
<p>If you use a full-page cache (WP Rocket, LiteSpeed Cache, W3 Total Cache, or your host's built-in cache), a PHP check that runs when WordPress renders the page <strong>doesn't run on a cached page</strong>. The cache serves the stored HTML without WordPress ever looking at the visitor's IP. Server-side blocker plugins usually document this and ask you to exclude protected pages from the cache.</p>
<p>Two ways around it:</p>
<ul>
<li><strong>Check at the edge</strong>: a Cloudflare WAF rule or Worker sees every request before the cache.</li>
<li><strong>Check in the browser and on submit</strong>: a small script on the page reports the visit and the form submit, so cached pages are covered too. The decision happens when the form is actually submitted.</li>
</ul>
<h2>4. Protect the forms, not the whole site</h2>
<p>Blocking every page for every VPN user is a blunt tool. The forms are where abuse costs you money, so put the friction there:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>Typical abuse</th>
<th>A reasonable response for risky submits</th>
</tr>
</thead>
<tbody><tr>
<td>Registration (<code>wp-login.php?action=register</code>, membership plugins)</td>
<td>Bot signups, fake accounts</td>
<td>A Turnstile check or email verification</td>
</tr>
<tr>
<td>Login (<code>wp-login.php</code>, WooCommerce My Account)</td>
<td>Credential stuffing</td>
<td>A short wait plus a challenge after failures</td>
</tr>
<tr>
<td>Contact and lead forms</td>
<td>Spam leads</td>
<td>A challenge for hosting networks only</td>
</tr>
<tr>
<td>WooCommerce checkout</td>
<td>Card testing, fraud</td>
<td>A challenge, or hold the order for review</td>
</tr>
</tbody></table>
<p>"Risky" should mean several signals together (a datacenter IP plus a brand-new account plus a burst of attempts), not a VPN on its own.</p>
<h2>5. Your options on WordPress</h2>
<p>There are three common routes, and they combine well:</p>
<ul>
<li><strong>Cloudflare WAF rules.</strong> If your site is behind Cloudflare, custom rules can block or challenge by ASN, country or Cloudflare's own threat signals, before the cache. Powerful, but you write and maintain the rules yourself, and you don't get a per-form view of what happened.</li>
<li><strong>A blocker plugin backed by an IP API.</strong> Plugins such as Proxy &amp; VPN Blocker (proxycheck.io) or VPN Guard (vpnapi.io) check the visitor IP against an API and block or redirect on pages you choose. Simple and effective for hard blocking; mind the caching caveat above and the API's daily quota.</li>
<li><strong>A monitoring-first plugin with form protection.</strong> Score every visit and form submit, see the reasons in a dashboard, and add friction only on the forms and signals that turn out to matter.</li>
</ul>
<h2>Where FindIP Shield fits</h2>
<p>Disclosure: we make FindIP Shield, a free plugin for the third route.</p>
<ul>
<li>Every visit, signup, login and WooCommerce checkout gets a risk score with the reasons: VPN, proxy, Tor, relay, hosting or datacenter network, or a known malicious IP.</li>
<li>It runs on regular pages and on <code>wp-login.php</code>, in the browser, so full-page caching doesn't skip it.</li>
<li>With WooCommerce active it adds cart, checkout, payment-failure and order-completion context, so you can see which orders came through anonymizing networks.</li>
<li>It doesn't block anything by default. When you're ready, you switch on form protection from the dashboard and choose what a risky visitor sees: a message, a short wait, or a Cloudflare Turnstile check.</li>
<li>It never reads form values, passwords, emails or payment details, and starts in strict privacy mode.</li>
<li>Setup is install, click <strong>Connect</strong>, pick your site. Free up to 10,000 events per site per day.</li>
</ul>
<p>It's on WordPress.org as <a href="https://wordpress.org/plugins/findip-shield/">FindIP Shield: VPN, Proxy &amp; Bot Traffic Detection</a>, and there's an <a href="https://www.findip.net/shield/demo">example dashboard with sample data</a> if you want to see what it shows before installing.</p>
<h2>The short version</h2>
<ol>
<li>Find out which networks your visitors come from: residential, hosting, VPN, Tor.</li>
<li>Monitor for a week before blocking anything.</li>
<li>Remember that page caching skips server-side checks; check at the edge or in the browser.</li>
<li>Add friction on the forms where abuse costs money, when several signals stack up.</li>
<li>Never block VPN users outright. Challenge them when the rest of the picture looks wrong.</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[How to stop free-tier abuse on an AI app (without killing signups)]]></title><description><![CDATA[Free credits on an AI app cost real tokens per account. A layered setup, with code, that makes farming not worth it.]]></description><link>https://findipnet.hashnode.dev/how-to-stop-free-tier-abuse-on-an-ai-app-without-killing-signups</link><guid isPermaLink="true">https://findipnet.hashnode.dev/how-to-stop-free-tier-abuse-on-an-ai-app-without-killing-signups</guid><category><![CDATA[SaaS]]></category><category><![CDATA[Security]]></category><category><![CDATA[AI]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[FindIP]]></dc:creator><pubDate>Thu, 22 Oct 2026 14:39:01 GMT</pubDate><content:encoded><![CDATA[<p>On most SaaS products a fake free account costs you a row in a database. On an AI app it costs you tokens. Every new account that burns its free credits is a bill, and the people who farm free tiers know it: new email, new browser profile, sometimes a VPN, same workload as yesterday.</p>
<p>The usual fixes each have a hole. Email verification stops nobody with a disposable inbox. A card on the free tier stops the abuse and most of your signups with it. IP rate limits lock out a whole office behind one NAT.</p>
<p>What works is layers, each cheap on its own, ordered so the first ones protect your bill even before you catch anyone. This is the setup, in the order we'd build it.</p>
<h2>1. Cap the blast radius first</h2>
<p>Before you try to detect anything, make sure the worst case is a number you chose.</p>
<ul>
<li><strong>A global daily budget for all free usage.</strong> When it's spent, free requests queue or wait until tomorrow. One bad night can't become a surprise invoice.</li>
<li><strong>A per-account daily cap</strong> that's lower than you think you need.</li>
<li><strong>Check both on the server, before the model call</strong>, not after.</li>
</ul>
<pre><code class="language-ts">// Before calling the model for a free-tier user
async function canSpendFree(userId: string, estTokens: number) {
  const today = new Date().toISOString().slice(0, 10);
  const [global, user] = await Promise.all([
    redis.incrby(`free:global:${today}`, estTokens),
    redis.incrby(`free:user:${userId}:${today}`, estTokens),
  ]);
  await redis.expire(`free:global:${today}`, 172800);
  await redis.expire(`free:user:${userId}:${today}`, 172800);
  return global &lt;= GLOBAL_FREE_DAILY &amp;&amp; user &lt;= USER_FREE_DAILY;
}
</code></pre>
<p>This doesn't stop farming. It makes farming boring and bounded, which is most of the battle.</p>
<h2>2. Make each account worth less</h2>
<p>Farming is economics. Lower the payout per account and most farmers stop.</p>
<ul>
<li><strong>Drip credits instead of one lump.</strong> "50 a day for a week" is far less worth farming than "350 now". An honest user barely notices.</li>
<li><strong>Start new accounts on a cheaper model.</strong> The good model unlocks after email verification and a bit of normal use. The farmer's cost per account goes up; yours goes down.</li>
<li><strong>Unlock more with trust</strong>: account age, normal usage, a verified email, or a card, but ask for the card only when an account looks risky (step 5).</li>
</ul>
<h2>3. Clean up the email layer</h2>
<p>Not because it stops determined people, but because it's an afternoon of work and removes the laziest farming.</p>
<pre><code class="language-ts">const DISPOSABLE = new Set(disposableDomains); // e.g. the open-source "disposable-email-domains" list

export function normalizeEmail(raw: string) {
  const [local, domain] = raw.trim().toLowerCase().split('@');
  const d = domain === 'googlemail.com' ? 'gmail.com' : domain;
  let l = local.split('+')[0];                 // drop +tags
  if (d === 'gmail.com') l = l.replace(/\./g, ''); // Gmail ignores dots
  return { email: `${l}@${d}`, disposable: DISPOSABLE.has(d) };
}
</code></pre>
<p>Store the normalized email with a unique index, and keep a hash of it when an account is deleted, so "delete and sign up again" doesn't reset the free tier.</p>
<h2>4. Group accounts instead of judging each one</h2>
<p>A single signal proves nothing. A VPN is common for privacy-minded users; a shared IP is every office and mobile carrier. What gives farmers away is that their accounts <strong>look alike</strong>:</p>
<ul>
<li><strong>Network type, not just IP.</strong> An office NAT or a mobile carrier is a residential or mobile ISP. Ten accounts in an hour from VPN exits and cloud servers are not. This distinction is what keeps your false positives down.</li>
<li><strong>Network changes inside one session</strong>: the IP, ASN or country switching mid-signup is a strong sign of a rotating proxy.</li>
<li><strong>Timing</strong>: a new signup minutes after the previous account ran out of credits.</li>
<li><strong>Workload</strong>: the same first prompts, files or project shape as an older account.</li>
</ul>
<p>Log these for every signup from day one. You can't cluster history you didn't keep.</p>
<h2>5. Add friction only where signals stack up</h2>
<p>Now use the signals, gently:</p>
<table>
<thead>
<tr>
<th>Signals</th>
<th>Response</th>
</tr>
</thead>
<tbody><tr>
<td>Nothing unusual</td>
<td>Straight in, normal free tier</td>
</tr>
<tr>
<td>One weak signal (a VPN, say)</td>
<td>Straight in, maybe the drip starts smaller</td>
</tr>
<tr>
<td>Several signals, or a known-bad network</td>
<td>A Turnstile check, email or phone verification before credits</td>
</tr>
<tr>
<td>Clearly the same person as a capped account</td>
<td>No free credits until they verify with a card</td>
</tr>
</tbody></table>
<p>The honest majority never sees any of this. The farmer sees it on every account.</p>
<h2>Where FindIP Shield fits</h2>
<p>Disclosure: we make FindIP Shield, a free tool that does the network part of steps 4 and 5. It scores each visit and form submit from 0 to 100 with the reasons (VPN, proxy, Tor, hosting or datacenter network, known malicious IP, IP changes during the session), and can add a short wait, a Turnstile check or a stop message for risky submits only, off until you switch it on. It scores the network, not the device: there's no device fingerprinting, so on its own it won't recognize the same laptop on a fresh profile. It never reads form values.</p>
<p>The browser side is one script tag:</p>
<pre><code class="language-html">&lt;script
  src="https://cdn.findip.net/shield/v1.js"
  data-site-key="pub_xxxxxxxxx"
  data-auto-track="true"
  data-privacy-mode="balanced"&gt;
&lt;/script&gt;
</code></pre>
<p>Send the Shield session ID with your signup request (<code>FindIP.getSession().sessionId</code>), then let your server make the decision, because anything decided in the browser can be bypassed:</p>
<pre><code class="language-ts">async function shieldVerdict(sessionId: string) {
  const res = await fetch('https://shield.findip.net/v1/shield/sessions/verify', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.SHIELD_SECRET_KEY}`, // sec_..., server only
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ session_id: sessionId, event: 'signup_attempt' }),
  });
  const v = await res.json();

  // Unknown is not safe: no session, or no IP intelligence for it.
  if (!v.verified || v.risk_status === 'unknown') return 'monitor';
  if (v.recommendation === 'block') return 'require_card';
  if (v.recommendation === 'challenge') return v.challenge_passed ? 'allow' : 'require_verification';
  return 'allow';
}
</code></pre>
<p>Combine that verdict with your own signals from steps 3 and 4, and feed it into the table in step 5. Shield is free up to 10,000 events per site per day; there's also a WordPress plugin, a Shopify app, a GTM template and a no-code Cloudflare integration if your signup page isn't hand-written.</p>
<h2>The short version</h2>
<ol>
<li>Cap global and per-account free spend on the server.</li>
<li>Drip credits and start new accounts on a cheaper model.</li>
<li>Normalize emails, block disposable domains, remember deleted accounts.</li>
<li>Cluster accounts by network type, timing and workload.</li>
<li>Add friction only where signals stack up, and never block VPN users outright.</li>
</ol>
<p>You won't stop every determined person. You don't need to: you need farming to cost them more than it saves, while honest users still get in with one click.</p>
]]></content:encoded></item></channel></rss>