<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pol Nisenblat</title>
    <description>The latest articles on DEV Community by Pol Nisenblat (@pol_nisenblat).</description>
    <link>https://dev.to/pol_nisenblat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3830161%2Faa1b5a61-e2c0-4a63-9d12-243239252365.png</url>
      <title>DEV Community: Pol Nisenblat</title>
      <link>https://dev.to/pol_nisenblat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pol_nisenblat"/>
    <language>en</language>
    <item>
      <title>We built official SDKs for 8 languages for our IP geolocation API — here's what we learned</title>
      <dc:creator>Pol Nisenblat</dc:creator>
      <pubDate>Mon, 13 Apr 2026 05:15:01 +0000</pubDate>
      <link>https://dev.to/pol_nisenblat/we-built-official-sdks-for-8-languages-for-our-ip-geolocation-api-heres-what-we-learned-119n</link>
      <guid>https://dev.to/pol_nisenblat/we-built-official-sdks-for-8-languages-for-our-ip-geolocation-api-heres-what-we-learned-119n</guid>
      <description>&lt;p&gt;After years of maintaining a single basic JavaScript client, we spent the first part of 2026 building proper SDKs for BigDataCloud across every major language. Here's what shipped and a few things we learned along the way.&lt;/p&gt;

&lt;p&gt;What we built&lt;/p&gt;

&lt;p&gt;Official SDKs for Node.js/TypeScript, Python, PHP, .NET/C#, Java, Go, Ruby and Rust — each covering all four of our API packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP Geolocation — city, country, ASN, hazard report, confidence area, timezone, user agent parsing&lt;/li&gt;
&lt;li&gt;Reverse Geocoding — GPS coordinates to locality, city, subdivision, country&lt;/li&gt;
&lt;li&gt;Phone &amp;amp; Email Verification — E.164 formatting, line type detection, MX validation, disposable detection&lt;/li&gt;
&lt;li&gt;Network Engineering — BGP prefixes, ASN peers, Tor exit nodes, CIDR lookups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also built free client-side libraries for React, Vue, React Native, Swift (iOS/macOS/watchOS), Kotlin (Android) and Flutter — GPS-first with automatic IP fallback, no API key needed.&lt;/p&gt;

&lt;p&gt;The design decisions that mattered&lt;/p&gt;

&lt;p&gt;One consistent pattern across all languages&lt;/p&gt;

&lt;p&gt;Every SDK follows the same structure: four API group objects on a single client, a fromEnvironment() factory reading BIGDATACLOUD_API_KEY, and a splitIntoPolygons() helper for confidence area handling. A Python developer and a Go developer should look at the code and immediately understand what the other one is doing.&lt;/p&gt;

&lt;p&gt;Confidence area polygons are tricky&lt;/p&gt;

&lt;p&gt;Our IP geolocation API returns a confidenceArea field — a flat array of coordinates that encodes multiple polygon rings. The closing coordinate of each ring matches its opening coordinate. This is simple in theory but breaks in practice when consumers treat the whole array as one polygon. Every SDK ships a SplitIntoPolygons() helper, and we documented the gotcha clearly.&lt;/p&gt;

&lt;p&gt;Phone validation needs explicit country context&lt;/p&gt;

&lt;p&gt;validatePhone(number) with no country hint silently uses the server's IP for country detection — which on a cloud server returns the wrong country for your users. We made countryCode a required parameter in every SDK. A bit more friction upfront, a lot less confusion later.&lt;/p&gt;

&lt;p&gt;asnNumeric needs to be long in Java&lt;/p&gt;

&lt;p&gt;Some ASN numbers exceed Integer.MAX_VALUE (2^31). We discovered this only after running the Java SDK against the live API and hitting a deserialization error on a real ASN. Every other language handles this implicitly — Java doesn't.&lt;/p&gt;

&lt;p&gt;The client-side fair use challenge&lt;/p&gt;

&lt;p&gt;The free client-side libraries use a no-key endpoint (api.bigdatacloud.net) that's governed by a fair use policy: only real-time device GPS coordinates, never pre-stored or server-side coordinates. We removed the reverseGeocode(lat, lng) override from the client libraries entirely — it would have been too easy to misuse the free endpoint by routing server-side batch geocoding through it.&lt;/p&gt;

&lt;p&gt;GraphQL&lt;/p&gt;

&lt;p&gt;We're one of the few geolocation providers with a GraphQL API. The Python and .NET SDKs include typed query builders — fluent interfaces that generate the GraphQL query string, give you IntelliSense, and make it obvious which fields cost bandwidth.&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Node.js
&lt;span class="go"&gt;npm install bigdatacloud

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Python
&lt;span class="go"&gt;pip install bigdatacloud

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Go
&lt;span class="go"&gt;go get github.com/bigdatacloudapi/bigdatacloud-go

&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Rust
&lt;span class="go"&gt;cargo add bigdatacloud
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Free tier on all packages, no credit card required. Full SDK list and install instructions at bigdatacloud.com/docs/sdks.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>sdk</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Free Location Detection in React — One Hook, Zero Configuration</title>
      <dc:creator>Pol Nisenblat</dc:creator>
      <pubDate>Wed, 18 Mar 2026 23:06:43 +0000</pubDate>
      <link>https://dev.to/pol_nisenblat/free-location-detection-in-react-one-hook-zero-configuration-24oo</link>
      <guid>https://dev.to/pol_nisenblat/free-location-detection-in-react-one-hook-zero-configuration-24oo</guid>
      <description>&lt;p&gt;Adding location awareness to a React app usually means signing up for a geocoding service, managing API keys, and writing fallback logic. What if you could skip all of that?&lt;/p&gt;

&lt;p&gt;30-Second Setup&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;bigdatacloudapi&lt;/span&gt;&lt;span class="sr"&gt;/react-reverse-geocode-clien&lt;/span&gt;&lt;span class="err"&gt;t
&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGeoLocation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@bigdatacloudapi/react-reverse-geocode-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGeoLocation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Detecting&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;📍&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;countryName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;principalSubdivision&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Detected&lt;/span&gt; &lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire integration. No API key, no account, no configuration.&lt;/p&gt;

&lt;p&gt;How It Works&lt;/p&gt;

&lt;p&gt;The useGeoLocation() hook implements a two-tier detection strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GPS first — requests the browser's geolocation (user sees a permission prompt)&lt;/li&gt;
&lt;li&gt;Automatic IP fallback — if GPS is denied or unavailable, resolves location from the user's IP address&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both paths return the identical JSON structure. Your UI code doesn't need to handle two different response formats.&lt;/p&gt;

&lt;p&gt;Why It's Free&lt;/p&gt;

&lt;p&gt;There's no catch. When the hook sends GPS coordinates, the browser also reveals its IP address. This anonymous pairing helps BigDataCloud continuously validate their IP geolocation accuracy — which they benchmark daily in a public accuracy report. You provide location context, they provide the geocoding. Fair exchange.&lt;/p&gt;

&lt;p&gt;Features&lt;/p&gt;

&lt;p&gt;• ✅ No API key — works out of the box&lt;br&gt;
• ✅ GPS with automatic IP fallback&lt;br&gt;
• ✅ 100+ languages ({ language: 'ja' } for Japanese)&lt;br&gt;
• ✅ Full TypeScript types&lt;br&gt;
• ✅ SSR/Next.js compatible&lt;br&gt;
• ✅ Manual trigger mode for "Detect My Location" buttons&lt;/p&gt;

&lt;p&gt;Multi-language Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGeoLocation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// data.countryName → "日本"&lt;/span&gt;
&lt;span class="c1"&gt;// data.city → "東京"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manual Trigger&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refresh&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGeoLocation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;manual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Detecting...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Detect My Location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next.js / SSR&lt;/p&gt;

&lt;p&gt;Works in client components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGeoLocation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@bigdatacloudapi/react-reverse-geocode-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fair Use&lt;/p&gt;

&lt;p&gt;The free client-side API is for production client-side use only. For development and testing, use the server-side API with a free API key. See the &lt;a href="https://www.bigdatacloud.com/support/fair-use-policy-for-free-client-side-reverse-geocoding-api" rel="noopener noreferrer"&gt;fair use policy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Links&lt;/p&gt;

&lt;p&gt;• 📦 &lt;a href="https://www.npmjs.com/package/@bigdatacloudapi/react-reverse-geocode-client" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;br&gt;
• 💻 &lt;a href="https://github.com/bigdatacloudapi/react-reverse-geocode-client" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;
• 🌐 &lt;a href="https://www.bigdatacloud.com/" rel="noopener noreferrer"&gt;BigDataCloud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also available for Vue/Nuxt: &lt;a class="mentioned-user" href="https://dev.to/bigdatacloudapi"&gt;@bigdatacloudapi&lt;/a&gt;/vue-reverse-geocode-client&lt;/p&gt;

&lt;p&gt;Canonical URL: &lt;a href="https://www.bigdatacloud.com/blog/free-location-detection-in-react" rel="noopener noreferrer"&gt;https://www.bigdatacloud.com/blog/free-location-detection-in-react&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
