<?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: Daniel Igel</title>
    <description>The latest articles on DEV Community by Daniel Igel (@grenzfrei).</description>
    <link>https://dev.to/grenzfrei</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%2F3982725%2F6c4b0484-702b-40c6-919f-93756e16fd33.png</url>
      <title>DEV Community: Daniel Igel</title>
      <link>https://dev.to/grenzfrei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grenzfrei"/>
    <language>en</language>
    <item>
      <title>Scraping Cloudflare-protected pages without running your own headless browser</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:55 +0000</pubDate>
      <link>https://dev.to/grenzfrei/scraping-cloudflare-protected-pages-without-running-your-own-headless-browser-4pig</link>
      <guid>https://dev.to/grenzfrei/scraping-cloudflare-protected-pages-without-running-your-own-headless-browser-4pig</guid>
      <description>&lt;p&gt;Most "just use Puppeteer" advice falls apart the moment the target sits behind Cloudflare's JS challenge. You end up maintaining a headless fleet, rotating fingerprints, and babysitting timeouts — for what should be a one-line fetch.&lt;/p&gt;

&lt;p&gt;I wrapped a challenge-solving backend behind a tiny REST API: you POST a URL and get back rendered HTML, plain text, or just the fields you want via CSS selectors. The challenge gets solved server-side, so your code stays a single HTTP call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://web-scraping-api-cloudflare-bypass.p.rapidapi.com/api/v1/extract'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: web-scraping-api-cloudflare-bypass.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"url":"https://example.com","selectors":{"title":"h1","price":".price"}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response gives you &lt;code&gt;{ "title": "...", "price": "..." }&lt;/code&gt; — no browser, no proxy rotation, no DOM parsing on your side. There's also &lt;code&gt;/api/v1/scrape&lt;/code&gt; if you just want the raw HTML or text of a page.&lt;/p&gt;

&lt;p&gt;Free tier to try it on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/web-scraping-api-cloudflare-bypass" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/web-scraping-api-cloudflare-bypass&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built this because I was tired of running a headless cluster for occasional scrapes. Happy to answer questions about the challenge-solving part or selector edge cases.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>node</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Cut signup spam: syntax + MX + disposable email validation in one call</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:52 +0000</pubDate>
      <link>https://dev.to/grenzfrei/cut-signup-spam-syntax-mx-disposable-email-validation-in-one-call-34m9</link>
      <guid>https://dev.to/grenzfrei/cut-signup-spam-syntax-mx-disposable-email-validation-in-one-call-34m9</guid>
      <description>&lt;p&gt;Client-side regex catches typos, not throwaway inboxes. By the time a fake &lt;code&gt;test@mailinator.com&lt;/code&gt; is in your DB, your activation rate and sender reputation already took the hit.&lt;/p&gt;

&lt;p&gt;This API does three checks in one request: RFC-5322 syntax, a live MX lookup (does the domain actually accept mail?), and a disposable/role-based check (&lt;code&gt;info@&lt;/code&gt;, &lt;code&gt;admin@&lt;/code&gt;, temp-mail domains). It also suggests fixes for obvious typos like &lt;code&gt;gmail.con&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validation-api37.p.rapidapi.com/api/v1/validate?email=test@gmail.con'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: email-validation-api37.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get back validity, MX status, &lt;code&gt;disposable&lt;/code&gt;/&lt;code&gt;role_based&lt;/code&gt; flags, and a &lt;code&gt;did_you_mean&lt;/code&gt; suggestion. There's a batch endpoint (&lt;code&gt;POST /api/v1/validate&lt;/code&gt;) for cleaning an existing list.&lt;/p&gt;

&lt;p&gt;Free tier on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/email-validation-api37" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/email-validation-api37&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built this to gate signups on a side project. Curious what your stack currently does for MX checks — happy to compare notes.&lt;/p&gt;

</description>
      <category>api</category>
      <category>saas</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Add geo-personalization with one IP lookup (IPv4/IPv6, batch)</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:48 +0000</pubDate>
      <link>https://dev.to/grenzfrei/add-geo-personalization-with-one-ip-lookup-ipv4ipv6-batch-1nj4</link>
      <guid>https://dev.to/grenzfrei/add-geo-personalization-with-one-ip-lookup-ipv4ipv6-batch-1nj4</guid>
      <description>&lt;p&gt;Geo-personalization — currency, language, "stores near you" — usually means shipping a 60 MB GeoIP database and keeping it updated, or paying per-seat for an SDK. For most apps you just need country + city from an IP.&lt;/p&gt;

&lt;p&gt;One GET does it, IPv4 and IPv6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://ip-geolocation-api20.p.rapidapi.com/api/v1/geo?ip=8.8.8.8'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: ip-geolocation-api20.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns country, region, city, lat/lon, timezone. There's &lt;code&gt;/api/v1/geo/me&lt;/code&gt; to resolve the caller's own IP (handy for edge functions) and &lt;code&gt;/api/v1/geo/batch&lt;/code&gt; for bulk enrichment of logs or signups.&lt;/p&gt;

&lt;p&gt;Free tier on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/ip-geolocation-api20" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/ip-geolocation-api20&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built this so I didn't have to bundle MaxMind into every small project. What do you use IP geo for — personalization, fraud, analytics?&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Drop-in sentiment, summary &amp; NER without managing an LLM key</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:45 +0000</pubDate>
      <link>https://dev.to/grenzfrei/drop-in-sentiment-summary-ner-without-managing-an-llm-key-3oil</link>
      <guid>https://dev.to/grenzfrei/drop-in-sentiment-summary-ner-without-managing-an-llm-key-3oil</guid>
      <description>&lt;p&gt;Adding "summarize this" or "is this review positive?" to an app shouldn't mean signing up for an LLM provider, managing a key, handling rate limits, and writing prompt+parsing glue. Sometimes you just want a JSON endpoint.&lt;/p&gt;

&lt;p&gt;Five NLP tasks, same shape, no LLM key on your side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://ai-text-analysis-api.p.rapidapi.com/api/v1/sentiment'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: ai-text-analysis-api.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"text":"The delivery was late but support fixed it instantly."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Endpoints: &lt;code&gt;/sentiment&lt;/code&gt;, &lt;code&gt;/summarize&lt;/code&gt;, &lt;code&gt;/entities&lt;/code&gt; (NER), &lt;code&gt;/classify&lt;/code&gt; (zero-shot into your own categories), &lt;code&gt;/keywords&lt;/code&gt;. Each returns clean JSON — drop it straight into your UI.&lt;/p&gt;

&lt;p&gt;Free tier on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/ai-text-analysis-api" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/ai-text-analysis-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built this to stop re-writing the same LLM plumbing in every project. What NLP task would you want as a one-liner?&lt;/p&gt;

</description>
      <category>api</category>
      <category>ai</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Generate OG / social-preview images on the fly (screenshots-as-a-service)</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:42 +0000</pubDate>
      <link>https://dev.to/grenzfrei/generate-og-social-preview-images-on-the-fly-screenshots-as-a-service-574l</link>
      <guid>https://dev.to/grenzfrei/generate-og-social-preview-images-on-the-fly-screenshots-as-a-service-574l</guid>
      <description>&lt;p&gt;Dynamic OG images and "preview this URL" thumbnails are a pain to self-host: you ship Playwright/Chromium, fight cold starts on serverless, and watch memory spike. For most use cases a hosted endpoint is enough.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://website-screenshot-api8.p.rapidapi.com/api/v1/screenshot?url=https://example.com&amp;amp;format=png&amp;amp;full_page=true'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: website-screenshot-api8.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full-page or viewport, PNG/JPEG/WebP. There's a &lt;code&gt;POST /api/v1/screenshot&lt;/code&gt; with the full option set (dimensions, delay, format) when you need more control.&lt;/p&gt;

&lt;p&gt;Free tier on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/website-screenshot-api8" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/website-screenshot-api8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built this to render social-preview cards without a headless cluster. What are you generating screenshots for — previews, monitoring, thumbnails?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>node</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Free-tier currency conversion straight from the ECB feed</title>
      <dc:creator>Daniel Igel</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:31:09 +0000</pubDate>
      <link>https://dev.to/grenzfrei/free-tier-currency-conversion-straight-from-the-ecb-feed-e5m</link>
      <guid>https://dev.to/grenzfrei/free-tier-currency-conversion-straight-from-the-ecb-feed-e5m</guid>
      <description>&lt;p&gt;Most currency APIs gate the daily ECB reference rates behind a paid plan — even though the source feed is public. If you just need "convert 100 USD to EUR" for a checkout or dashboard, that's overkill.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://currency-exchange-rate-api11.p.rapidapi.com/api/v1/convert?from=USD&amp;amp;to=EUR&amp;amp;amount=100'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: currency-exchange-rate-api11.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns the converted amount + the rate used. Also &lt;code&gt;/api/v1/rates&lt;/code&gt; (all rates for a base), &lt;code&gt;/api/v1/currencies&lt;/code&gt; (supported list), and &lt;code&gt;/api/v1/history&lt;/code&gt; (a currency's historical rates).&lt;/p&gt;

&lt;p&gt;Free tier on RapidAPI: &lt;a href="https://rapidapi.com/danieligel/api/currency-exchange-rate-api11" rel="noopener noreferrer"&gt;https://rapidapi.com/danieligel/api/currency-exchange-rate-api11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built this on top of the ECB daily feed so small projects don't pay for reference rates. What do you use FX conversion for?&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>fintech</category>
    </item>
  </channel>
</rss>
