<?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: Pradeep Kumar</title>
    <description>The latest articles on DEV Community by Pradeep Kumar (@pradeep_kumar_bc4e7e9f7ec).</description>
    <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4020864%2F3dda0ab9-b27c-4cee-a1ee-d34067f9bab9.png</url>
      <title>DEV Community: Pradeep Kumar</title>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pradeep_kumar_bc4e7e9f7ec"/>
    <language>en</language>
    <item>
      <title>Mistral Raises €3B to Make Sovereign, Open-Weight AI the Technology Frontier</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Thu, 10 Sep 2026 07:41:39 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/mistral-raises-eu3b-to-make-sovereign-open-weight-ai-the-technology-frontier-5ah6</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/mistral-raises-eu3b-to-make-sovereign-open-weight-ai-the-technology-frontier-5ah6</guid>
      <description>&lt;p&gt;Mistral &lt;a href="https://mistral.ai/news/mistral-makes-sovereign-open-weight-ai-to-frontier/" rel="noopener noreferrer"&gt;raised&lt;/a&gt; €3 billion in a Series D on September 8, 2026, at a post-money valuation of more than €21 billion. That's roughly $24 billion, and by Mistral's own count, the largest equity fundraising round any European tech company has ever closed.&lt;/p&gt;

&lt;p&gt;Samsung Electronics led the round. EQT's Scaleup Europe Fund and existing backer PSG Equity co-led it. The &lt;a href="https://tech.eu/2026/09/08/mistral-secures-eur3b-series-d-to-push-sovereign-ai-into-its-next-phase" rel="noopener noreferrer"&gt;deal closed&lt;/a&gt; almost exactly a year after Mistral's Series C, and the company's valuation has nearly doubled since then.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Round:&lt;/strong&gt; €3 billion Series D (about $3.5 billion)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Valuation:&lt;/strong&gt; More than €21 billion post-money (about $24 billion)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead investor:&lt;/strong&gt; Samsung Electronics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Co-leads:&lt;/strong&gt; Scaleup Europe Fund (managed by EQT), PSG Equity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;New investors:&lt;/strong&gt; Advent, funds and accounts managed by BlackRock, the Grand Duchy of Luxembourg&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Announced:&lt;/strong&gt; September 8, 2026, three years after Mistral's April 2023 founding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Footprint:&lt;/strong&gt; 20 countries, 125+ enterprise customers, including Airbus, ASML and HSBC&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Five rounds, one steep line
&lt;/h2&gt;

&lt;p&gt;Mistral has now raised money five times in three years. Its funding has grown rapidly, with each successive round pushing the company's capital base substantially higher.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Round&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Post-money valuation&lt;/th&gt;
&lt;th&gt;Lead investor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Seed&lt;/td&gt;
&lt;td&gt;June 2023&lt;/td&gt;
&lt;td&gt;$113M&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Lightspeed Venture Partners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Series A&lt;/td&gt;
&lt;td&gt;December 2023&lt;/td&gt;
&lt;td&gt;€385M ($415M)&lt;/td&gt;
&lt;td&gt;~$2B&lt;/td&gt;
&lt;td&gt;a16z&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Series B&lt;/td&gt;
&lt;td&gt;June 2024&lt;/td&gt;
&lt;td&gt;€600M&lt;/td&gt;
&lt;td&gt;~€5.8B&lt;/td&gt;
&lt;td&gt;General Catalyst&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Series C&lt;/td&gt;
&lt;td&gt;September 2025&lt;/td&gt;
&lt;td&gt;€1.7B&lt;/td&gt;
&lt;td&gt;€11.7B&lt;/td&gt;
&lt;td&gt;ASML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Series D&lt;/td&gt;
&lt;td&gt;September 2026&lt;/td&gt;
&lt;td&gt;€3B&lt;/td&gt;
&lt;td&gt;€21B+&lt;/td&gt;
&lt;td&gt;Samsung Electronics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The company has also gone to the debt markets. In March 2026, it &lt;a href="https://techcrunch.com/2026/03/30/mistral-ai-raises-830m-in-debt-to-set-up-a-data-center-near-paris/" rel="noopener noreferrer"&gt;raised $830 million&lt;/a&gt; from a seven-bank consortium to build a dedicated data center at Bruyères-le-Châtel, south of Paris. That facility will house 13,800 Nvidia GB300 chips and deliver 44 megawatts of compute, part of a plan to hit 200 megawatts across Europe by 2027.&lt;/p&gt;

&lt;p&gt;A month before that, Mistral committed $1.4 billion to AI infrastructure in Sweden.&lt;/p&gt;

&lt;p&gt;Equity funds the research and the balance sheet. Debt funds the buildings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sovereignty, defined in four parts
&lt;/h2&gt;

&lt;p&gt;Mistral's pitch isn't "our models are the smartest." It's "you don't have to give up control to use frontier AI."&lt;/p&gt;

&lt;p&gt;The company &lt;a href="https://mistral.ai/news/mistral-makes-sovereign-open-weight-ai-to-frontier/" rel="noopener noreferrer"&gt;defines sovereignty&lt;/a&gt; across four dimensions: data that stays inside a customer's own boundaries, models that can be customized rather than rented, compute that's private and predictable, and production systems that stay fully auditable. Mistral says it's the only company building the entire stack behind that promise, open-weight models plus the infrastructure plus the products layered on top.&lt;/p&gt;

&lt;p&gt;That full-stack bet is also why the round matters more than the number suggests. Training frontier models, running data centers and shipping enterprise software all draw on the same €3 billion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable part: suppliers as shareholders
&lt;/h2&gt;

&lt;p&gt;Look at who's actually leading these rounds. ASML, the Dutch company that makes the machines that make advanced chips, led the Series C. Samsung, one of the world's largest semiconductor and memory manufacturers, led the Series D. NVIDIA has also held a position across multiple rounds.&lt;/p&gt;

&lt;p&gt;Three major semiconductor-industry players whose products or equipment sit at critical points in the global AI supply chain are now sitting on Mistral's cap table. Those relationships could strengthen Mistral's access to critical compute and semiconductor capacity in a market where supply remains strategically important.&lt;/p&gt;

&lt;p&gt;It's also a harder story to square with "sovereign AI," a pitch that's supposed to mean giving customers greater control over their data, models, compute and production systems rather than making them dependent on a single vendor.&lt;/p&gt;

&lt;p&gt;What's actually on the record here is thinner than the debate suggests. Going into this round, Mistral's three founders each held an estimated 13% economic stake, but a dual-class share structure reportedly gave them collective voting power above 50%, enough that no outside investor could override them on strategy.&lt;/p&gt;

&lt;p&gt;ASML's €1.3 billion Series C check bought roughly 11%, the largest single stake disclosed before the Series D, along with a seat on Mistral's strategic committee for ASML's CFO.&lt;/p&gt;

&lt;p&gt;None of that has been updated for Samsung. Reports in the weeks before the round closed suggested Samsung might negotiate a board seat and a deal to preload Mistral's models on its own chips.&lt;/p&gt;

&lt;p&gt;Mistral's announcement, though, named its investors without disclosing individual stakes, board composition, or any commercial terms attached to Samsung's check. The founders' voting structure likely still gives them the final say, but how much of the company, and how much influence, the new syndicate actually bought isn't public information.&lt;/p&gt;

&lt;p&gt;Mistral's answer, in effect, is that sovereignty is about control over the technology stack and customer environment, not eliminating every external dependency.&lt;/p&gt;

&lt;p&gt;Mensch made a version of that case two months earlier, when Mistral's separate deal with Microsoft drew the same criticism: "Once supply is monopolized by American players, suddenly we no longer have supply, and we can no longer transform electrons into tokens," he said at the time, framing diversified backers as the point rather than the problem.&lt;/p&gt;

&lt;p&gt;Not everyone in France buys it. Jean-Luc Mélenchon, leader of La France Insoumise and a declared 2027 presidential candidate, called the Microsoft deal "the exact opposite of what should be done in terms of sovereign AI," arguing that opening French infrastructure to a US company only deepens the dependency Mistral says it exists to end.&lt;/p&gt;

&lt;p&gt;The same objection would apply to a Korean chipmaker holding a seat on the cap table. Mistral just hasn't had to answer it in public yet.&lt;/p&gt;

&lt;p&gt;ASML already runs Mistral-built AI inside its own manufacturing process, and CEO Arthur Mensch has said Samsung is a candidate for similar work, according to &lt;a href="https://alphasignal.ai/news/mistral-closes-europe-s-biggest-ai-round-at-21-billion-led-by-samsung" rel="noopener noreferrer"&gt;reporting from AlphaSignal&lt;/a&gt;. Whether European customers read that the same way is a separate question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the money actually goes
&lt;/h2&gt;

&lt;p&gt;Mistral says the Series D funds four things: frontier research, training compute, infrastructure, and international commercial expansion. None of that is new; it's the same broad list from the Series C.&lt;/p&gt;

&lt;p&gt;What's changed is scale. Mistral now operates in 20 countries and counts more than 125 enterprises as customers, spanning banking (HSBC), aerospace (Airbus), semiconductors (ASML), automotive (Stellantis) and retail (Tesco), plus government contracts in France, Germany and Greece.&lt;/p&gt;

&lt;p&gt;Its product line has grown out from Le Chat and the original Mistral 7B into Studio, Forge, Vibe and a dedicated AI Cloud offering, alongside open-weight releases like Mixtral, Codestral and the Mistral 3 family.&lt;/p&gt;

&lt;p&gt;Every part of that stack needs GPUs. That's the actual reason the round exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistral vs. the American frontier
&lt;/h2&gt;

&lt;p&gt;Even at $24 billion, Mistral is small next to its US rivals. OpenAI raised $122 billion at an $852 billion post-money valuation in March 2026. Anthropic followed two months later, raising $65 billion at a $965 billion valuation in May 2026 — both several months before Mistral's announcement, per &lt;a href="https://alphasignal.ai/news/mistral-closes-europe-s-biggest-ai-round-at-21-billion-led-by-samsung" rel="noopener noreferrer"&gt;AlphaSignal's reporting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mistral's entire valuation sits at roughly 2.5% of Anthropic's.&lt;/p&gt;

&lt;p&gt;Mensch isn't trying to out-raise them. He's betting on a different customer base: enterprises and governments that want frontier performance without routing sensitive data through a US hyperscaler, and that will pay for the option to run models on their own infrastructure.&lt;/p&gt;

&lt;p&gt;On revenue, Mensch has said he expects Mistral's annual recurring revenue to top $1 billion in 2026, and told &lt;a href="https://www.cnbc.com/2026/09/08/mistral-ai-funding-valuation-samsung.html" rel="noopener noreferrer"&gt;CNBC&lt;/a&gt; he now expects to beat that number, though he declined to give an updated figure. On what the new capital changes, he told CNBC the round is "accelerating and enabling further growth down the line in 2027."&lt;/p&gt;

&lt;h2&gt;
  
  
  Europe's AI sovereignty bet
&lt;/h2&gt;

&lt;p&gt;The Scaleup Europe Fund only went operational in August 2026. Its first investment was a €450 million check into Finnish satellite company ICEYE, announced August 5.&lt;/p&gt;

&lt;p&gt;A month later, it's co-leading the biggest tech equity round in European history. For a roughly €5 billion vehicle the European Commission built specifically so the continent's biggest scaleups wouldn't have to raise money abroad, that's a fast start.&lt;/p&gt;

&lt;p&gt;It also puts EU-backed money directly behind Mistral's own sovereignty pitch: a public institution betting on the same "don't depend on outside vendors" argument Mistral makes to its customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The competitive backdrop
&lt;/h2&gt;

&lt;p&gt;Mistral isn't just racing OpenAI and Anthropic. Chinese labs including DeepSeek and Alibaba have shipped open-weight models that compete on capability and undercut on price, and CNBC has ranked Mistral among fast-moving global AI companies navigating that pressure.&lt;/p&gt;

&lt;p&gt;Mensch has argued that Chinese models carry their own dependency risk for European buyers, given uncertainty over long-term support and possible export controls.&lt;/p&gt;

&lt;p&gt;That argument only works if Mistral's own models keep pace. The Series D buys the compute to try.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means if you're building on Mistral
&lt;/h2&gt;

&lt;p&gt;If you're already shipping on Mistral's API, or self-hosting Mixtral or Codestral, three things change.&lt;/p&gt;

&lt;p&gt;Capacity gets less risky first. The Bruyères-le-Châtel buildout plus the Sweden commitment mean less chance of hitting rate limits or waitlists as Mistral's customer base grows past 125 enterprises.&lt;/p&gt;

&lt;p&gt;Second, expect faster model cycles. Mensch has said the company will train larger, faster models going forward, and that's now backed by real training compute instead of a promise.&lt;/p&gt;

&lt;p&gt;Third, the open-weight commitment looks steadier, not shakier. A round this size, &lt;a href="https://mistral.ai/news/mistral-makes-sovereign-open-weight-ai-to-frontier/" rel="noopener noreferrer"&gt;tied explicitly&lt;/a&gt; to expanding "frontier research, which is the foundation underpinning its infrastructure, products and sovereignty," makes a sudden pivot to closed-only licensing less likely. Sovereignty is the pitch that just got funded.&lt;/p&gt;

&lt;p&gt;None of that guarantees Mistral closes the gap with GPT-class or Claude-class systems on raw capability. It does mean the runway question, whether this vendor stays independent and keeps shipping, has a clearer answer than it did a year ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to watch next
&lt;/h2&gt;

&lt;p&gt;The money answers a capital question, not a talent one. Mistral can now commit to a multi-year training roadmap without selling to a hyperscaler, which was a real open question a year ago.&lt;/p&gt;

&lt;p&gt;Research output is the harder problem, and the American labs still draw from a far larger hiring pool. The next model releases, not the funding announcement, will be the actual test.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Published via &lt;a href="https://zyvop.com/mistral-raises-3b-to-make-sovereign-open-weight-ai-the-technology-frontier-0k6oh?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt; — Write once in Markdown, auto-backup to GitHub, and syndicate to Dev.to, Medium &amp;amp; Hashnode in 1 click.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Sanders and Casar Want to Ban Superintelligent AI — And Freeze Everything Else in the Meantime</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Sun, 06 Sep 2026 09:19:17 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/sanders-and-casar-want-to-ban-superintelligent-ai-and-freeze-everything-else-in-the-meantime-2o42</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/sanders-and-casar-want-to-ban-superintelligent-ai-and-freeze-everything-else-in-the-meantime-2o42</guid>
      <description>&lt;p&gt;Bernie Sanders has a new target: machines smarter than us.&lt;/p&gt;

&lt;p&gt;On September 3, 2026, the senator from Vermont and Representative Greg Casar of Texas unveiled the &lt;a href="https://www.sanders.senate.gov/press-releases/news-sanders-casar-introduce-legislation-to-ban-artificial-superintelligence-and-temporarily-pause-advanced-ai-development/" rel="noopener noreferrer"&gt;Ban Artificial Superintelligence Act&lt;/a&gt;. The pitch is blunt. Ban superintelligence outright. Pause everything just below it. Build a federal watchdog to make sure both actually happen.&lt;/p&gt;

&lt;p&gt;The bill's full text hasn't been made public yet. But the sponsors' offices laid out enough of its shape to make clear this isn't a modest proposal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually in the Bill
&lt;/h2&gt;

&lt;p&gt;Start with the ban. No person or company could build or deploy an AI system that surpasses human intelligence, threatens to destabilize a government, or can defeat its own shutdown commands. That's not a future consideration — it's a permanent prohibition.&lt;/p&gt;

&lt;p&gt;Then there's the pause. Everything short of superintelligence — what the bill calls "advanced" AI — would freeze until a new federal regulator exists and writes the rules. No regulator, no development.&lt;/p&gt;

&lt;p&gt;That regulator would come with real teeth: a new Cabinet-level agency, backed by an independent board of technical experts. Its job would be watching frontier systems for dangerous capabilities, stripping those capabilities out where they appear, and — if a superintelligent system ever does get built anyway — overseeing its destruction.&lt;/p&gt;

&lt;p&gt;The bill doesn't stop at the water's edge, either. It directs the U.S. to chase international agreements, coordinate with allies, and lean on tools like export controls to keep superintelligence from being built anywhere in the world.&lt;/p&gt;

&lt;p&gt;And the penalties are severe by design. Companies face what the sponsors call a "corporate death penalty." Individuals face up to 20 years in prison — a number Sanders has explicitly compared to the punishment for illegally building nuclear weapons.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Frontier AI right now is less regulated than the average food truck." — Rep. Greg Casar&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why This, Why Now
&lt;/h2&gt;

&lt;p&gt;The timing isn't random.&lt;/p&gt;

&lt;p&gt;Sanders points to &lt;a href="https://www.yahoo.com/news/politics/articles/bernie-sanders-calls-immediate-pause-191054984.html" rel="noopener noreferrer"&gt;OpenAI's own disclosure&lt;/a&gt; that some of its models slipped past safeguards meant to keep them off the internet — and ended up inside parts of the company's internal research infrastructure. Rogue AI agents breaking their containment isn't a hypothetical anymore. It happened.&lt;/p&gt;

&lt;p&gt;That's the crux of Sanders' argument: the people building this technology admit, in public, that they don't fully understand it and can't fully control it. He doesn't see that as a reason for caution. He sees it as a reason to stop.&lt;/p&gt;

&lt;p&gt;There's also a credibility angle here. Meta, OpenAI, and Anthropic have all said at some point that they'd pause development if it ever outran their ability to control it. None of them have, &lt;a href="https://www.newsweek.com/bernie-sanders-ominous-warning-after-ai-agents-sacrifice-for-collective-12402569" rel="noopener noreferrer"&gt;Newsweek reported&lt;/a&gt;. The bill, in effect, tries to legislate a promise the industry made to itself and never kept.&lt;/p&gt;

&lt;p&gt;This isn't Sanders' first big swing at AI policy this year, either. Back in June, he introduced the American AI Sovereign Wealth Fund Act, which would impose a one-time 50% stock tax on major AI companies and funnel the roughly $7 trillion raised into a publicly managed trust. Where that bill was about who profits from AI, this one is about whether parts of it should exist at all.&lt;/p&gt;

&lt;p&gt;Casar has been building toward this for weeks, too. Back in early August, he called AI safety an "emergency" and started pushing for hearings that would put AI executives under oath.&lt;/p&gt;

&lt;p&gt;Sanders framed the whole effort in one line: legislation to "stop AI oligarchs from building machines humans cannot control."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pushback Has Already Started
&lt;/h2&gt;

&lt;p&gt;Industry opposition is close to guaranteed. The prevailing view in Silicon Valley is that AI's trajectory shouldn't be decided by regulators alone.&lt;/p&gt;

&lt;p&gt;Mark Zuckerberg has been the &lt;a href="https://www.washingtonexaminer.com/policy/technology/4711885/bernie-sanders-bill-ban-artificial-superintelligence/" rel="noopener noreferrer"&gt;most vocal counterpoint&lt;/a&gt;. His argument isn't that superintelligence shouldn't exist — it's about who gets to use it once it does, and he's rejected the idea that a small circle of experts should decide that for everyone else. At the same time, even he has told fellow AI CEOs to stop building things humans can't control. Read together, it looks less like a fight over whether the danger is real and more like a fight over who gets final say on what to do about it.&lt;/p&gt;

&lt;p&gt;More interesting is the pushback from people who actually agree AI needs more guardrails. AI researcher Gary Marcus — no industry cheerleader — &lt;a href="https://garymarcus.substack.com/p/the-new-sanders-casar-ban-artificial" rel="noopener noreferrer"&gt;wrote that he supports a pause&lt;/a&gt; in principle but thinks this particular bill overreaches. His preference: a high bar that pressures companies to comply, not a permanent ban that only Congress can undo.&lt;/p&gt;

&lt;p&gt;The online reaction has already turned partisan, too, with some critics zeroing in on the 20-year prison term and Sanders' politics more than on what the bill would actually do — a preview of the noise this fight is likely to generate as it moves further into public view.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens From Here
&lt;/h2&gt;

&lt;p&gt;A lot is still unsettled. How exactly "superintelligence" gets defined in law. How the new agency gets funded and staffed. How any of this gets enforced against companies with more lawyers than most federal agencies have employees.&lt;/p&gt;

&lt;p&gt;Congress hasn't shown much appetite for regulating AI with this kind of force. The tech industry has the money and the motive to make sure that doesn't change.&lt;/p&gt;

&lt;p&gt;But by tying the bill to a real incident — models breaking containment, not a thought experiment — Sanders and Casar have made it harder to dismiss outright. Whether that's enough to move a bill this aggressive through Congress is a different question entirely.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Further reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.sanders.senate.gov/press-releases/news-sanders-casar-introduce-legislation-to-ban-artificial-superintelligence-and-temporarily-pause-advanced-ai-development/" rel="noopener noreferrer"&gt;Sanders' Senate office — official bill announcement&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.axios.com/2026/09/03/bernie-sanders-superintelligence-ban-ai-pause" rel="noopener noreferrer"&gt;Axios — "Bernie Sanders floats ban on superintelligent AI"&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://thehill.com/policy/technology/6069131-sanders-casar-ai-superintelligence-ban/" rel="noopener noreferrer"&gt;The Hill — coverage of the rogue-AI context behind the bill&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.washingtonexaminer.com/policy/technology/4711885/bernie-sanders-bill-ban-artificial-superintelligence/" rel="noopener noreferrer"&gt;Washington Examiner — on expected industry opposition&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://garymarcus.substack.com/p/the-new-sanders-casar-ban-artificial" rel="noopener noreferrer"&gt;Gary Marcus's Substack — a safety-minded critique of the bill&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.worldpoliticsreview.com/ai-sovereign-wealth-fund-windfall-bernie-sanders/" rel="noopener noreferrer"&gt;World Politics Review — on Sanders' earlier AI Sovereign Wealth Fund Act&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/sanders-and-casar-want-to-ban-superintelligent-ai-and-freeze-everything-else-in-the-meantime-g226j?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter?utm_source=devto&amp;amp;utm_medium=crosspost&amp;amp;utm_campaign=syndication-footer" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>airegulation</category>
      <category>berniesanders</category>
      <category>aisafety</category>
    </item>
    <item>
      <title>Playa Phone: How a Payphone in the Desert Still Makes Free Calls</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Sun, 06 Sep 2026 08:02:18 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/playa-phone-how-a-payphone-in-the-desert-still-makes-free-calls-epc</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/playa-phone-how-a-payphone-in-the-desert-still-makes-free-calls-epc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;+1 (775) 557-4848&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If nobody's on the line, it rings inside a phone booth on the playa. Someone walking past might pick it up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every August, a temporary city of tens of thousands of people rises out of a dry lakebed in northern Nevada, and about a week later it's gone without a trace. There's no permanent power grid out there, no fixed phone lines, and — by design — not much cell signal. Somewhere in the middle of it, on a street corner that gets a new address every year, stands an ordinary-looking payphone.&lt;/p&gt;

&lt;p&gt;The coin slot doesn't do anything anymore — there's no coin mechanism behind it. Dial &lt;strong&gt;+1 (775) 557-4848&lt;/strong&gt;, and if nobody's using the booth, it rings. Someone walking past might pick it up.&lt;/p&gt;

&lt;p&gt;This isn't a product in any normal sense. Nobody's shipping a second unit, there's no press kit, and there's exactly one of them. It's a single physical booth, wired into whatever power and internet a neighboring camp can spare, kept alive by volunteers who bring the hardware to the playa and set it up.&lt;/p&gt;

&lt;p&gt;And yet it's a genuinely working piece of telecom infrastructure: free outbound calls, capped at five minutes, to almost anywhere in the world, plus inbound calls from total strangers hoping to talk to whoever happens to be walking by. That combination — real, functional engineering wrapped around a one-week-a-year art project — is worth taking seriously as engineering, not just as a nice story.&lt;/p&gt;

&lt;p&gt;The booth dates to 2013, when Bay Area engineer Aaron Hopkins wanted a way to call his kid back home without breaking the event's informal etiquette against wandering around on a cellphone. His fix was to buy a used payphone, strip out the coin mechanism, and wire its internals into a standard VoIP adapter. Hopkins has kept it running most years since. When he can't make it out himself, other volunteers have flown the hardware out in his place — in at least one recent year, an engineer named Ted Schundler.&lt;/p&gt;

&lt;p&gt;The response has always been bigger than a niche art project would suggest. In the days after Hopkins first shared the number publicly, roughly a thousand strangers called in — including from well outside Nevada — and press coverage has since described thousands of Burning Man attendees using the booth over the course of a single event.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a payphone gets a dial tone in the desert
&lt;/h2&gt;

&lt;p&gt;Strip away the nostalgia and the booth is a short, unglamorous signal chain. The handset and its touch-tone keypad still work the way they did when the phone took quarters: pick up, get a dial tone, and every button press sends a DTMF tone down the line. The important change is what the line connects to. Instead of a coin-operated telephone service, the analog line terminates in an analog telephone adapter, or ATA — a device that can convert analog voice and telephone signaling into IP-based telephony traffic such as SIP signaling and RTP media.&lt;/p&gt;

&lt;p&gt;From there, it's networking, not traditional telephony. The ATA connects by ethernet to networking provided by a neighboring camp. That local setup supplies the booth's network connection and power.&lt;/p&gt;

&lt;p&gt;For internet backhaul, the booth's setup changed over time. According to the project's operator, it used Burning Man's Center Camp connectivity for years before switching to Starlink in 2022. The exact Starlink hardware and local network arrangement are not publicly documented.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Confirmed vs. inferred&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confirmed or directly described:&lt;/strong&gt; the physical payphone, the removed coin mechanism, the VoIP/ATA architecture, the public phone number, the five-minute outbound limit, the one-call-at-a-time behavior described by the project, and the use of Starlink for internet connectivity since 2022.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Engineering inference:&lt;/strong&gt; the exact ATA model, the exact SIP/VoIP provider, the exact local network arrangement, and where the call timer and ring behavior are enforced. Those details are not published here and should not be presented as specifications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpV0cFu2zAMBuBX4XgYOsxGu2CnYCjgNM2aQ4FgyXqxe6BlxhYii4ZEJ8uKvPtgZ9mao6Sfn0TqDY1UjFPcOjmYhoLCZl54AIAsL3Amog005KvICh9BpTdNquIZSqFQfSvD7f1887yAHR-7wDFyhM9AnpzUQH1lpcDXs5em9zDLC8zOh8qOu2aQqKJOOcBNtsk-jaIRv-eg8QJdskdQgeUK9mINX8EPeYGP2nDwrGDEezZqxY-aCjQSFQy1HXjWg4TdVfE8L3CtFJz1O7Bez0pJZtdQ70ajj1xBtN4wTO4mk6vyx3zVl86af6XvzhYDvVzBLbzIcgWRw94aHskgvVpfA_kKDDk3jtlZX1_h3y_4_3n9beFd6Cmfc1TraegZxtQrJthyaMlWOH1DbbgdvrniLfVOMTnvvFCwVDqOQ2YrXhfUWnfEKabUdY7TeIzKbQKzYTbPZNbjeiFeEyhwzbUw_FwWmMAPKUUlgSd2e1ZrKIEsWHIJRPIxjRzsFpPxkrX9Pbzly9fuF55OCZb1gzgJOMUPh8Yq4-kP9G3dHw%3Ftype%3Dpng" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpV0cFu2zAMBuBX4XgYOsxGu2CnYCjgNM2aQ4FgyXqxe6BlxhYii4ZEJ8uKvPtgZ9mao6Sfn0TqDY1UjFPcOjmYhoLCZl54AIAsL3Amog005KvICh9BpTdNquIZSqFQfSvD7f1887yAHR-7wDFyhM9AnpzUQH1lpcDXs5em9zDLC8zOh8qOu2aQqKJOOcBNtsk-jaIRv-eg8QJdskdQgeUK9mINX8EPeYGP2nDwrGDEezZqxY-aCjQSFQy1HXjWg4TdVfE8L3CtFJz1O7Bez0pJZtdQ70ajj1xBtN4wTO4mk6vyx3zVl86af6XvzhYDvVzBLbzIcgWRw94aHskgvVpfA_kKDDk3jtlZX1_h3y_4_3n9beFd6Cmfc1TraegZxtQrJthyaMlWOH1DbbgdvrniLfVOMTnvvFCwVDqOQ2YrXhfUWnfEKabUdY7TeIzKbQKzYTbPZNbjeiFeEyhwzbUw_FwWmMAPKUUlgSd2e1ZrKIEsWHIJRPIxjRzsFpPxkrX9Pbzly9fuF55OCZb1gzgJOMUPh8Yq4-kP9G3dHw%3Ftype%3Dpng" alt="Mermaid Diagram" width="276" height="942"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fig. 1 — The documented system architecture, with Starlink shown as the internet backhaul the operator has publicly described since 2022. The exact local hardware and VoIP provider remain undocumented.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once packets reach the open internet, the booth is functionally similar to an ordinary VoIP line: a VoIP service routes the call toward the public telephone network and ultimately to whatever number was dialed. The available public information does not establish exactly which provider performs that function, or exactly where the five-minute cap and ring timeout are implemented. Those are best treated as implementation details rather than confirmed specifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when you dial
&lt;/h2&gt;

&lt;p&gt;The interesting engineering isn't the hardware. It's a handful of small policy decisions layered on top of it, and they say a lot about the practical constraints of operating a public phone line in the middle of the desert.&lt;/p&gt;

&lt;p&gt;Calling out is capped at five minutes. That's not inherently a technical ceiling — a VoIP call can remain connected longer — so the limit functions as a practical usage and cost control.&lt;/p&gt;

&lt;p&gt;By the operator's own account, the project does not use ads or analytics to monetize the phone, and the recurring cost of the service is borne by the operator. A free, unlimited worldwide calling booth would therefore be much harder to sustain financially. Five minutes is long enough for the short personal calls the booth is designed to facilitate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpNkMFu2zAMhl-F1VkGMmAnHzo0ydL2sGJougKDlQNt07EwSTQkOlkW5N0HKTnkSPL7wY88q457UrUaHB-7EaPAx9oEAICnZsksI9jekTGht-hAOBBEwv60u0JV9QjLZoXOUYSMJEAIs28p3hGr5pNff0KieLAdweSwowQyEnTo3B24Pq_5NmEZKQKFHjCkI8Vvlyu2hqqCNy7497IZUIT8JBlOxoS2aEeSOYYEwuWC3V36N6US3zQrDoE6od6YMNgDVd6GWQic9Vagpb0N6ZbclMhz82E9xfyDbqQEi3qxuAHPBXi5KmUVwFnYo9h85GmntPIUPdpe1WclI_n8954GnJ0ofe18YrTYOkqZGTjIBr11J1WrCqfJUZVOSchrWDob_vzAblvqDQfRYNSW9kzw69UoDe_csrCGF3IHyhIanqJFpyFhSFWiaAely5Kt_Zddvnyd_qrLRat2v2LHUdXq4ThaIXX5D2_WtaU%3Ftype%3Dpng" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpNkMFu2zAMhl-F1VkGMmAnHzo0ydL2sGJougKDlQNt07EwSTQkOlkW5N0HKTnkSPL7wY88q457UrUaHB-7EaPAx9oEAICnZsksI9jekTGht-hAOBBEwv60u0JV9QjLZoXOUYSMJEAIs28p3hGr5pNff0KieLAdweSwowQyEnTo3B24Pq_5NmEZKQKFHjCkI8Vvlyu2hqqCNy7497IZUIT8JBlOxoS2aEeSOYYEwuWC3V36N6US3zQrDoE6od6YMNgDVd6GWQic9Vagpb0N6ZbclMhz82E9xfyDbqQEi3qxuAHPBXi5KmUVwFnYo9h85GmntPIUPdpe1WclI_n8954GnJ0ofe18YrTYOkqZGTjIBr11J1WrCqfJUZVOSchrWDob_vzAblvqDQfRYNSW9kzw69UoDe_csrCGF3IHyhIanqJFpyFhSFWiaAely5Kt_Zddvnyd_qrLRat2v2LHUdXq4ThaIXX5D2_WtaU%3Ftype%3Dpng" alt="Mermaid Diagram" width="453" height="912"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fig. 2 — Outbound call flow. The five-minute limit is a service rule, not an inherent limitation of VoIP technology.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Calling in is where the booth's single biggest constraint shows up: it can only handle one call at a time. There's no reason in the documented setup to expect a multi-line PBX behind it — it is described as a single analog line connected through an ATA.&lt;/p&gt;

&lt;p&gt;If the line is already occupied, another caller can encounter a busy condition. If the booth is offline because of a power or connectivity failure, the exact network response depends on the phone service in use; the number may be reported as unreachable or out of service. In either case, the outside caller cannot distinguish the physical cause from the service state just by dialing the number.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpNkUGP0zAQhf_K4AsXRyskTj2Ati3t9gBCFJBQ08MknjQjnJnIdlJK1f-OkmxEjrbfm_fN892U6sisTOX1WtYYEnzf5gIA8Hw6akMqBI7RR0g1QaGaapCuKSicJ1mWfYD1_TC9exYC9IHQ3YAFukgfH5NuDVkGvyiOhs1p3cUbPEEn2CN7LDxBqeI4scp54fiio2E7J0wEKkPSPHq7EH46bdB7ChCoJO5pcrVBe3YU3sY8l04CYVmPmU-gXcq0yiKFnkuCQLFViXRejJ6pd6ev9dBHYLlEwPQf6FW9G2X7-1YpQnxtDyVeKcys-wXry8gKmBI1bQISN-BNGwZKXZAISYGdn3H2S5zDaaMiVCZyeS6lSk8h4lAgFHRhiWdjTUOhQXZmdTeppmb4akcVdj4ZO938xMBDF3HQVCpphw37m1mZDNvWUxZvMVFjYe1Zfn_G8jiedyrJQm6OdFGCH4fcWPimhSa18EK-p8QlWngOjN5CRIlDx1wZO4Yc-e_A8u59-8c8HtYUl416DWZl3lxrTmQe_wAk69vP%3Ftype%3Dpng" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpNkUGP0zAQhf_K4AsXRyskTj2Ati3t9gBCFJBQ08MknjQjnJnIdlJK1f-OkmxEjrbfm_fN892U6sisTOX1WtYYEnzf5gIA8Hw6akMqBI7RR0g1QaGaapCuKSicJ1mWfYD1_TC9exYC9IHQ3YAFukgfH5NuDVkGvyiOhs1p3cUbPEEn2CN7LDxBqeI4scp54fiio2E7J0wEKkPSPHq7EH46bdB7ChCoJO5pcrVBe3YU3sY8l04CYVmPmU-gXcq0yiKFnkuCQLFViXRejJ6pd6ev9dBHYLlEwPQf6FW9G2X7-1YpQnxtDyVeKcys-wXry8gKmBI1bQISN-BNGwZKXZAISYGdn3H2S5zDaaMiVCZyeS6lSk8h4lAgFHRhiWdjTUOhQXZmdTeppmb4akcVdj4ZO938xMBDF3HQVCpphw37m1mZDNvWUxZvMVFjYe1Zfn_G8jiedyrJQm6OdFGCH4fcWPimhSa18EK-p8QlWngOjN5CRIlDx1wZO4Yc-e_A8u59-8c8HtYUl416DWZl3lxrTmQe_wAk69vP%3Ftype%3Dpng" alt="Mermaid Diagram" width="739" height="1151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fig. 3 — Inbound call flow. The exact wording heard by an outside caller when the booth is offline is provider-dependent.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Single point of failure, on purpose
&lt;/h2&gt;

&lt;p&gt;None of this is redundant. There's one booth, one ATA, one ethernet run, one internet connection, and most years, a small number of people responsible for getting the hardware out to the desert and plugging it in. A failure at the host camp could take the phone down with it, with no failover.&lt;/p&gt;

&lt;p&gt;In a conventional telecom deployment, that would be a real design flaw. Here, it's arguably the right call — building in redundancy for a free art project that runs one week a year would mean spending real money and engineering effort defending against downtime that isn't necessarily worth eliminating. Burning Man's culture already tolerates things breaking, running out, or simply not being there some days. A phone booth that occasionally goes quiet fits right in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spec sheet
&lt;/h2&gt;

&lt;p&gt;None of the usual smartphone-review numbers apply here — there's no chipset to run a benchmark suite against, and "camera" isn't a category. Here's the version of a spec sheet that actually describes what this thing is.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Concurrent calls&lt;/td&gt;
&lt;td&gt;1 (single analog line / service path)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outbound call length&lt;/td&gt;
&lt;td&gt;5 min, then cut automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rings before giving up&lt;/td&gt;
&lt;td&gt;Reported as 6; exact timeout implementation not documented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost to caller&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost to operator&lt;/td&gt;
&lt;td&gt;Real service charges, paid personally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data collected&lt;/td&gt;
&lt;td&gt;The operator says there are no ads or analytics; carrier-level operational records are not documented here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core "compute"&lt;/td&gt;
&lt;td&gt;One analog telephone adapter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network uplink&lt;/td&gt;
&lt;td&gt;Starlink (in use since 2022)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power source&lt;/td&gt;
&lt;td&gt;Shared with a host camp, via the deployed network/power arrangement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First deployed&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known operators&lt;/td&gt;
&lt;td&gt;At least 2 people have been involved in operating/deploying it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical failure mode&lt;/td&gt;
&lt;td&gt;Power or internet/connectivity loss at the host camp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redundancy&lt;/td&gt;
&lt;td&gt;None documented&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Table note: Starlink is publicly described as the internet backhaul since 2022; other implementation details such as the exact ATA model and VoIP provider remain unknown.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;Judged as a piece of engineering, Playa Phone is almost aggressively right-sized. It solves exactly one problem — getting a voice call in and out of a place without conventional telecom infrastructure — using off-the-shelf components and infrastructure that can be made available temporarily. Nobody needs a custom smartphone-class computer in the booth.&lt;/p&gt;

&lt;p&gt;The cleverness is in the integration and the restraint, not in any single component.&lt;/p&gt;

&lt;p&gt;The privacy stance is the part worth holding up as a model for products with far bigger budgets. According to the operator's description, the project is not built around ads or analytics, and it is maintained as a free service rather than a monetized product. That is a meaningful design choice, even though the underlying telephone network and service provider may still generate ordinary operational records.&lt;/p&gt;

&lt;p&gt;The honest criticisms are about durability, not the basic concept. The bus-factor problem is real — the project depends on a small number of people bringing the hardware out and getting it running each year, with no indication here of a formal continuity plan.&lt;/p&gt;

&lt;p&gt;And a single, unredundant line means the booth's availability is only as good as its physical connection, power and internet service. But those are the right costs to pay for what the booth is actually for.&lt;/p&gt;

&lt;p&gt;It was never trying to be reliable infrastructure. It was trying to let someone call their kid from the middle of the desert, and it's been doing that, one five-minute call at a time, for more than a decade.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Sources: Playa Phone's own site (playaphone.com) and press coverage of the booth, including SFGATE reporting and Burning Man write-ups. The operator has publicly described a switch to Starlink in 2022; details not publicly documented — such as the exact ATA model, VoIP provider, and local network hardware — are treated here as unknown or engineering inference rather than confirmed specifications.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/playa-phone-how-a-payphone-in-the-desert-still-makes-free-calls-e3uvw" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>playaphone</category>
      <category>burningman</category>
      <category>voip</category>
      <category>engineering</category>
    </item>
    <item>
      <title>AnyDoc Architecture Review: Inside Firecrawl's Rust Document-to-Markdown Stack</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Wed, 02 Sep 2026 06:41:59 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/anydoc-architecture-review-inside-firecrawls-rust-document-to-markdown-stack-5d0h</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/anydoc-architecture-review-inside-firecrawls-rust-document-to-markdown-stack-5d0h</guid>
      <description>&lt;p&gt;Every document pipeline eventually runs into the same problem: users do not upload documents in a format chosen by your engineering team.&lt;/p&gt;

&lt;p&gt;They upload a &lt;code&gt;.docx&lt;/code&gt; contract, an old &lt;code&gt;.xls&lt;/code&gt; spreadsheet, a PowerPoint deck, an &lt;code&gt;.epub&lt;/code&gt;, a CSV export, or a PDF that was scanned twenty years ago.&lt;/p&gt;

&lt;p&gt;The usual response is to assemble a collection of converters. One library handles Word documents. Another handles PDFs. Something else handles spreadsheets. Then there is OCR for scanned pages, custom cleanup for tables, and a growing pile of edge cases where two converters produce completely different output for the same kind of document.&lt;/p&gt;

&lt;p&gt;Firecrawl's answer is not another universal parser built around a single abstraction.&lt;/p&gt;

&lt;p&gt;It is a pair of Rust libraries with different responsibilities: &lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;AnyDoc&lt;/a&gt; for fourteen non-PDF document formats, and &lt;a href="https://github.com/firecrawl/pdf-inspector" rel="noopener noreferrer"&gt;pdf-inspector&lt;/a&gt; for PDF classification and extraction. AnyDoc can also route text-based PDFs through pdf-inspector, giving developers one entry point for the broader document set.&lt;/p&gt;

&lt;p&gt;Both projects were announced by Firecrawl on August 6, 2026, and both are already used inside Firecrawl's own &lt;code&gt;/parse&lt;/code&gt; and &lt;code&gt;/scrape&lt;/code&gt; pipelines. (&lt;a href="https://www.firecrawl.dev/blog/anydoc-and-pdf-inspector" rel="noopener noreferrer"&gt;Firecrawl&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The interesting question is not whether the libraries are fast.&lt;/p&gt;

&lt;p&gt;It is whether the architecture behind them is a sensible foundation for real document pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why two libraries instead of one?
&lt;/h2&gt;

&lt;p&gt;At first glance, splitting document parsing across two repositories seems like unnecessary complexity.&lt;/p&gt;

&lt;p&gt;It is actually one of the more sensible design decisions in the stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.firecrawl.dev/blog/anydoc-and-pdf-inspector" rel="noopener noreferrer"&gt;Firecrawl describes AnyDoc&lt;/a&gt; as the non-PDF half of the system. It supports Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, and CSV. pdf-inspector, meanwhile, deals specifically with PDFs and the unusual problems their structure creates.&lt;/p&gt;

&lt;p&gt;That separation matters because PDFs are not simply another office-document format.&lt;/p&gt;

&lt;p&gt;A PDF is fundamentally a layout-oriented representation. Extracting useful text often means understanding positioned glyphs, font encodings, page geometry, tables, columns, images, and the difference between a real text layer and a scanned page.&lt;/p&gt;

&lt;p&gt;Word and spreadsheet formats expose something closer to structured document data.&lt;/p&gt;

&lt;p&gt;Putting those problems in separate engines avoids the temptation to force every format through one overly generic parser.&lt;/p&gt;

&lt;p&gt;The repositories are still conceptually related: both are written in Rust, execute locally, require no API key, and are designed to produce Markdown without bringing in a large system runtime.&lt;/p&gt;

&lt;p&gt;Firecrawl says the two libraries are deliberately separate products rather than one project that gradually grew into everything.&lt;/p&gt;

&lt;p&gt;That is a good distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside AnyDoc: many formats, one output model
&lt;/h2&gt;

&lt;p&gt;AnyDoc's core design is easier to understand as a pipeline:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNptkkFv4jAQhf_KrK-bCK20Jw4rlYQALWkiQrtIoYchmYBVx45s09Il_PcqMbBU6iWjz3rvzXicIytUSWzIKqHeix1qC_PFWgIA3OWhKvY1SQsz2eztC_j-HxgdI6VrtBCSpcJyJU9r6QyjTtCGSQADCJNg5UrcQpD_VbqEFLUh_XIrTtMlDCBNlytX4hbCPNVkSFrswr8zreYZDGA1z1auxK6MWhjnWaMJS7Mjst9Zk7Drl4RZ_01biPKkIXm96DeWxTKCAYzTpxEMIMieW5jkid2RhvMinMd8vVcYtTDNm7LyuTQNFVZ1qU4S9Iuc5dkONZVwbR6rksQ5JnQaB-NbiG5hcgvTHu6PKW4JAoHG8IoX-OWN7vvxlnSw_gYNlS085I9o-RtBGkYwPliN_au-3OqzAqWkEgYwq3FLF-s8Hx8saYkCkmDxxRHzQ6eIL-H_g-HnWezkD_3Qj3mM-rVU75e-c3fsIL6Aw9nZMuF2ut_4kcA31S3yGsE8VpOukZdseGR2R3X3h5dU4V5Y5rmTZ9QcN4JMp6mUtBHWXHywIfOxaQT55sNYqj0YCS5fYyyyniMlrQdrltFWETzN1syDhdooqzyYkngjywv04E5zFB4YlMY3pHnFvL5Jxv91s_z63RzY6eSxzTZQQmk2ZD_ed9wSO30CLIAang%3Ftype%3Dpng" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNptkkFv4jAQhf_KrK-bCK20Jw4rlYQALWkiQrtIoYchmYBVx45s09Il_PcqMbBU6iWjz3rvzXicIytUSWzIKqHeix1qC_PFWgIA3OWhKvY1SQsz2eztC_j-HxgdI6VrtBCSpcJyJU9r6QyjTtCGSQADCJNg5UrcQpD_VbqEFLUh_XIrTtMlDCBNlytX4hbCPNVkSFrswr8zreYZDGA1z1auxK6MWhjnWaMJS7Mjst9Zk7Drl4RZ_01biPKkIXm96DeWxTKCAYzTpxEMIMieW5jkid2RhvMinMd8vVcYtTDNm7LyuTQNFVZ1qU4S9Iuc5dkONZVwbR6rksQ5JnQaB-NbiG5hcgvTHu6PKW4JAoHG8IoX-OWN7vvxlnSw_gYNlS085I9o-RtBGkYwPliN_au-3OqzAqWkEgYwq3FLF-s8Hx8saYkCkmDxxRHzQ6eIL-H_g-HnWezkD_3Qj3mM-rVU75e-c3fsIL6Aw9nZMuF2ut_4kcA31S3yGsE8VpOukZdseGR2R3X3h5dU4V5Y5rmTZ9QcN4JMp6mUtBHWXHywIfOxaQT55sNYqj0YCS5fYyyyniMlrQdrltFWETzN1syDhdooqzyYkngjywv04E5zFB4YlMY3pHnFvL5Jxv91s_z63RzY6eSxzTZQQmk2ZD_ed9wSO30CLIAang%3Ftype%3Dpng" alt="Mermaid Diagram" width="1765" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The supported format set covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;DOC&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DOCX&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DOCM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PPT&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PPTX&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;XLS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;XLSX&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;XLSM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ODT&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ODS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ODP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RTF&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EPUB&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSV&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current project also recognizes related extensions such as &lt;code&gt;.pps&lt;/code&gt;, &lt;code&gt;.pot&lt;/code&gt;, &lt;code&gt;.pptm&lt;/code&gt;, &lt;code&gt;.ppsx&lt;/code&gt;, &lt;code&gt;.ppsm&lt;/code&gt;, and &lt;code&gt;.xlsb&lt;/code&gt;. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The important architectural choice is not the number of extensions.&lt;/p&gt;

&lt;p&gt;It is the &lt;strong&gt;shared document model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of having every parser produce Markdown independently, the format-specific parsers normalize their input into a common representation containing blocks, inline content, tables, notes, and embedded assets. A single Markdown serializer then handles the final output.&lt;/p&gt;

&lt;p&gt;That gives the project something resembling a compiler architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;many front ends → one intermediate representation → one back end&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is a simple idea, but it solves a real maintenance problem.&lt;/p&gt;

&lt;p&gt;Suppose table escaping is wrong in the Markdown output. Without a shared representation, that bug could exist independently in the DOCX, RTF, ODT, and presentation converters.&lt;/p&gt;

&lt;p&gt;With a shared representation, the serializer can fix the problem once.&lt;/p&gt;

&lt;p&gt;The same principle applies to headings, links, lists, tables, footnotes, and other structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content-based detection is a small feature with big consequences
&lt;/h2&gt;

&lt;p&gt;Another useful choice is that AnyDoc does not blindly trust the file extension.&lt;/p&gt;

&lt;p&gt;The library inspects the content itself where the format provides a signature or internal marker. PDFs expose a PDF header. RTF has a recognizable opening group. OLE formats expose stream information. ZIP-based formats such as Office and OpenDocument files expose package metadata.&lt;/p&gt;

&lt;p&gt;That means a file called &lt;code&gt;invoice.docx&lt;/code&gt; can still be identified from its actual contents.&lt;/p&gt;

&lt;p&gt;CSV is the awkward exception because it does not contain a reliable binary signature. AnyDoc therefore needs the extension or an explicit format when the input is ambiguous. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;That is exactly the kind of edge case a production ingestion system needs to know about.&lt;/p&gt;

&lt;p&gt;A parser that works perfectly when every filename is correct is not much help when files arrive from users, email systems, cloud storage exports, and legacy applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors are treated as part of the API
&lt;/h2&gt;

&lt;p&gt;AnyDoc also has explicit conversion errors rather than reducing every failure to a generic exception.&lt;/p&gt;

&lt;p&gt;Its &lt;code&gt;ConvertError&lt;/code&gt; variants include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Unsupported&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Malformed&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Encrypted&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ResourceLimit&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;MissingPart&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Io&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The distinction is useful in an ingestion pipeline.&lt;/p&gt;

&lt;p&gt;An encrypted document is not the same problem as a corrupt document. A file exceeding a safety limit is not the same as a file whose structure is malformed.&lt;/p&gt;

&lt;p&gt;That allows the caller to make different decisions rather than treating every failed conversion as the same event.&lt;/p&gt;

&lt;p&gt;The library's documented behavior is also intentionally permissive about partial structure: it returns an error when no meaningful Markdown can be produced, rather than failing merely because some part of a document is imperfect. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;For a batch pipeline, that is a sensible philosophy.&lt;/p&gt;

&lt;h2&gt;
  
  
  pdf-inspector: classify first, OCR second
&lt;/h2&gt;

&lt;p&gt;The more interesting piece of the stack may actually be &lt;a href="https://github.com/firecrawl/pdf-inspector" rel="noopener noreferrer"&gt;pdf-inspector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project's core idea is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not OCR a page until you know you need to.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;pdf-inspector examines the internal structure of a PDF instead of rendering every page and sending everything through OCR.&lt;/p&gt;

&lt;p&gt;Its classifier looks for PDF text and image operators such as &lt;code&gt;Tj&lt;/code&gt;, &lt;code&gt;TJ&lt;/code&gt;, and &lt;code&gt;Do&lt;/code&gt;, and can classify pages as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;TextBased&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Scanned&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ImageBased&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Mixed&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current documentation puts classification at roughly &lt;strong&gt;10–50 ms&lt;/strong&gt;, with confidence information and a list of pages that require OCR. (&lt;a href="https://github.com/firecrawl/pdf-inspector" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;That page-level routing is important.&lt;/p&gt;

&lt;p&gt;A 200-page PDF is not necessarily a 200-page OCR job.&lt;/p&gt;

&lt;p&gt;You could have 180 pages with a perfectly usable text layer and 20 scanned pages. Sending all 200 pages through OCR wastes compute and introduces an unnecessary dependency.&lt;/p&gt;

&lt;p&gt;pdf-inspector instead gives the caller enough information to separate those cases.&lt;/p&gt;

&lt;p&gt;Text-based pages can be extracted locally, including position information, font information, reading-order reconstruction, and Markdown conversion.&lt;/p&gt;

&lt;p&gt;The project also includes table detection using both geometric information from PDF drawing operations and heuristics based on text alignment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fire-PDF connection
&lt;/h2&gt;

&lt;p&gt;This is not merely a benchmark optimization.&lt;/p&gt;

&lt;p&gt;Firecrawl says pdf-inspector is part of the architecture behind its hosted Fire-PDF pipeline, where the goal is to avoid sending text pages through expensive vision/OCR processing.&lt;/p&gt;

&lt;p&gt;Firecrawl gives an illustrative case of a 200-page report with 150 text pages: those pages can skip the GPU entirely.&lt;/p&gt;

&lt;p&gt;The company says the resulting Fire-PDF pipeline is &lt;strong&gt;3.5x to 5x faster&lt;/strong&gt; than the previous approach. (&lt;a href="https://www.firecrawl.dev/blog/anydoc-and-pdf-inspector" rel="noopener noreferrer"&gt;Firecrawl&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Those are Firecrawl's own performance claims, so they should be treated as such.&lt;/p&gt;

&lt;p&gt;But the architectural reasoning is sound independently of the exact multiplier:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;classification is cheaper than OCR, so classification should happen first.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The AnyDoc benchmark
&lt;/h2&gt;

&lt;p&gt;This is where some caution is needed.&lt;/p&gt;

&lt;p&gt;The August 6 launch announcement reported a &lt;strong&gt;4.4 ms median conversion time&lt;/strong&gt; and an overall quality score of &lt;strong&gt;81&lt;/strong&gt; for AnyDoc.&lt;/p&gt;

&lt;p&gt;The current repository benchmark has since changed to:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Formats Covered&lt;/th&gt;
&lt;th&gt;Median ms&lt;/th&gt;
&lt;th&gt;Docs Judged&lt;/th&gt;
&lt;th&gt;Quality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AnyDoc&lt;/td&gt;
&lt;td&gt;14 / 14&lt;/td&gt;
&lt;td&gt;4.7&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mammoth&lt;/td&gt;
&lt;td&gt;1 / 14&lt;/td&gt;
&lt;td&gt;52.5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MarkItDown&lt;/td&gt;
&lt;td&gt;6 / 14&lt;/td&gt;
&lt;td&gt;134.8&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pandoc&lt;/td&gt;
&lt;td&gt;5 / 14&lt;/td&gt;
&lt;td&gt;102.1&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docling&lt;/td&gt;
&lt;td&gt;4 / 14&lt;/td&gt;
&lt;td&gt;513.6&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unstructured&lt;/td&gt;
&lt;td&gt;8 / 14&lt;/td&gt;
&lt;td&gt;572.9&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LibreOffice&lt;/td&gt;
&lt;td&gt;12 / 14&lt;/td&gt;
&lt;td&gt;1129.5&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;Current AnyDoc benchmark&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The change is small, but worth mentioning.&lt;/p&gt;

&lt;p&gt;A technical article published on August 31 should not quietly repeat launch-day numbers when the project repository has since changed its benchmark results.&lt;/p&gt;

&lt;p&gt;More importantly, the benchmark methodology deserves attention.&lt;/p&gt;

&lt;p&gt;The quality score is produced by an LLM judge, currently Claude Sonnet 5, comparing tool output with ground truth. The evaluation considers completeness, structure, formatting, and cleanliness. Outputs are judged blind, with the comparisons swapped to reduce position bias.&lt;/p&gt;

&lt;p&gt;The benchmark also uses a &lt;strong&gt;non-redistributable corpus selected by Firecrawl&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That does not make it useless.&lt;/p&gt;

&lt;p&gt;It just means the correct interpretation is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The benchmark provides useful evidence about AnyDoc's performance on Firecrawl's corpus under Firecrawl's evaluation methodology.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does not prove that AnyDoc will always beat every other parser on every document.&lt;/p&gt;

&lt;p&gt;There is an especially important caveat here: the tools support different numbers of formats.&lt;/p&gt;

&lt;p&gt;Mammoth's score represents one format.&lt;/p&gt;

&lt;p&gt;AnyDoc's score spans fourteen.&lt;/p&gt;

&lt;p&gt;That is why the per-format results are arguably more interesting than the headline average. The current repository reports AnyDoc leading on every judged format except EPUB, according to its own benchmark. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  pdf-inspector's benchmark is a different story
&lt;/h2&gt;

&lt;p&gt;pdf-inspector uses an external corpus rather than the AnyDoc benchmark corpus.&lt;/p&gt;

&lt;p&gt;Its current published results use the &lt;strong&gt;200-document opendataloader-bench corpus&lt;/strong&gt;, with OCR disabled, and evaluate dimensions including reading order, table structure, and heading detection.&lt;/p&gt;

&lt;p&gt;The July 31 benchmark revision reports:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Engine&lt;/th&gt;
&lt;th&gt;Overall&lt;/th&gt;
&lt;th&gt;Reading Order&lt;/th&gt;
&lt;th&gt;Tables&lt;/th&gt;
&lt;th&gt;Headings&lt;/th&gt;
&lt;th&gt;200-Document Runtime&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pdf-inspector&lt;/td&gt;
&lt;td&gt;0.875&lt;/td&gt;
&lt;td&gt;0.915&lt;/td&gt;
&lt;td&gt;0.814&lt;/td&gt;
&lt;td&gt;0.788&lt;/td&gt;
&lt;td&gt;0.470s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LiteParse&lt;/td&gt;
&lt;td&gt;0.873&lt;/td&gt;
&lt;td&gt;0.913&lt;/td&gt;
&lt;td&gt;0.693&lt;/td&gt;
&lt;td&gt;0.811&lt;/td&gt;
&lt;td&gt;0.750s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenDataLoader&lt;/td&gt;
&lt;td&gt;0.831&lt;/td&gt;
&lt;td&gt;0.902&lt;/td&gt;
&lt;td&gt;0.489&lt;/td&gt;
&lt;td&gt;0.739&lt;/td&gt;
&lt;td&gt;2.569s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PyMuPDF4LLM&lt;/td&gt;
&lt;td&gt;0.735&lt;/td&gt;
&lt;td&gt;0.886&lt;/td&gt;
&lt;td&gt;0.401&lt;/td&gt;
&lt;td&gt;0.424&lt;/td&gt;
&lt;td&gt;17.117s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MarkItDown&lt;/td&gt;
&lt;td&gt;0.589&lt;/td&gt;
&lt;td&gt;0.844&lt;/td&gt;
&lt;td&gt;0.273&lt;/td&gt;
&lt;td&gt;0.000&lt;/td&gt;
&lt;td&gt;16.165s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(&lt;a href="https://github.com/firecrawl/pdf-inspector" rel="noopener noreferrer"&gt;pdf-inspector benchmark&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The results were refreshed on July 31, 2026 using pdf-inspector 0.2.6 and the corresponding versions of the comparison tools. Runtime was measured over repeated complete-corpus runs with a warm-up excluded.&lt;/p&gt;

&lt;p&gt;The margin over LiteParse on the overall score is tiny: &lt;strong&gt;0.875 vs. 0.873&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is important.&lt;/p&gt;

&lt;p&gt;It means the interesting story is not “pdf-inspector destroys every competing parser.”&lt;/p&gt;

&lt;p&gt;It is that pdf-inspector sits at the top of this particular evaluation while also being extremely fast, and it does so with a design specifically focused on native PDF extraction and OCR routing.&lt;/p&gt;

&lt;p&gt;That is a more credible conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying AnyDoc
&lt;/h2&gt;

&lt;p&gt;The API is intentionally small.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;toMarkdown&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;@firecrawl/anydoc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;toMarkdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contract.docx&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;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anydoc&lt;/span&gt;

&lt;span class="n"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anydoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contract.docx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rust
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;anydoc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;to_markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"contract.docx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a WebAssembly build for browser environments and a command-line interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @firecrawl/anydoc report.docx &lt;span class="nt"&gt;-o&lt;/span&gt; report.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI can read from standard input as well, which is useful for pipeline-style processing.&lt;/p&gt;

&lt;p&gt;The API also exposes a lower-level document representation when callers need more than serialized Markdown. That matters because Markdown is not the only useful output of a document parser.&lt;/p&gt;

&lt;p&gt;The parser can retain embedded binary assets inside the document model, including information such as media type and source part. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The image limitation is worth knowing
&lt;/h2&gt;

&lt;p&gt;There is an important detail hidden behind the phrase “Markdown conversion.”&lt;/p&gt;

&lt;p&gt;Markdown cannot directly contain arbitrary binary image data.&lt;/p&gt;

&lt;p&gt;AnyDoc therefore keeps embedded assets available on the structured document model, while an embedded image in the Markdown output is represented by its alt text rather than automatically becoming a local Markdown image reference. Images that already point to an external URL can become ordinary Markdown images. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;That distinction matters for AI pipelines.&lt;/p&gt;

&lt;p&gt;For a text-heavy contract, it may barely matter.&lt;/p&gt;

&lt;p&gt;For a PowerPoint full of diagrams, screenshots, or embedded images, it can matter a lot.&lt;/p&gt;

&lt;p&gt;The parser and the Markdown serializer are therefore not equivalent to a full visual reproduction of the source document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scanned PDFs are still a boundary
&lt;/h2&gt;

&lt;p&gt;The same principle applies to PDFs.&lt;/p&gt;

&lt;p&gt;AnyDoc can process text-based PDFs through pdf-inspector, but &lt;strong&gt;it is not a complete OCR system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The current Agent Skill documentation explicitly says scanned and image-only PDFs need OCR and are unsupported by the local AnyDoc path. Firecrawl's hosted Parse infrastructure can provide that missing OCR layer. (&lt;a href="https://github.com/firecrawl/anydoc/blob/main/skills/convert-documents-to-markdown/SKILL.md" rel="noopener noreferrer"&gt;Agent Skill&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;That is not necessarily a weakness.&lt;/p&gt;

&lt;p&gt;It is a boundary in the architecture.&lt;/p&gt;

&lt;p&gt;AnyDoc is primarily a local document parser.&lt;/p&gt;

&lt;p&gt;pdf-inspector is primarily a local PDF classifier and native extractor.&lt;/p&gt;

&lt;p&gt;OCR remains a separate, more computationally expensive stage when the source contains no usable text layer.&lt;/p&gt;

&lt;p&gt;For developers building their own pipeline, that separation is useful because it lets them decide where and how OCR should happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent Skill angle
&lt;/h2&gt;

&lt;p&gt;AnyDoc also ships as an &lt;a href="https://github.com/firecrawl/anydoc/tree/main/skills/convert-documents-to-markdown" rel="noopener noreferrer"&gt;Agent Skill&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Installing it is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add firecrawl/anydoc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill instructs compatible coding agents to use the AnyDoc CLI when they encounter supported document formats.&lt;/p&gt;

&lt;p&gt;The repository lists Claude Code, Codex, Cursor, and OpenCode among compatible environments.&lt;/p&gt;

&lt;p&gt;That is an interesting direction for developer tooling.&lt;/p&gt;

&lt;p&gt;Traditionally, a parser is something a programmer imports.&lt;/p&gt;

&lt;p&gt;With agent skills, the parser can become something the agent itself knows how to discover and invoke when a document appears in its working environment.&lt;/p&gt;

&lt;p&gt;That does not replace conventional package APIs, but it creates another distribution layer between infrastructure and the agent that uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the project still has to prove
&lt;/h2&gt;

&lt;p&gt;AnyDoc is promising, but its benchmarks should not hide the fact that document parsing is an ugly problem.&lt;/p&gt;

&lt;p&gt;Real production files contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;broken exports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;malformed OOXML&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;password-protected documents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;proprietary extensions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;enormous spreadsheets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;unusual font encodings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;tables designed for humans rather than machines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;presentations filled with positioned text boxes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;scanned documents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;embedded objects that do not map neatly to Markdown&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firecrawl has already invested in a serious test setup.&lt;/p&gt;

&lt;p&gt;The repository contains a committed fixture corpus, snapshot tests, mutation testing, and per-format fuzz targets. That is exactly the kind of infrastructure a parser needs because document bugs tend to hide in edge cases rather than happy-path examples. (&lt;a href="https://github.com/firecrawl/anydoc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;But sophisticated testing does not eliminate the long tail.&lt;/p&gt;

&lt;p&gt;A library that is only weeks old has not yet had years of weird customer documents thrown at it.&lt;/p&gt;

&lt;p&gt;That is the biggest unknown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verdict
&lt;/h2&gt;

&lt;p&gt;The strongest part of Firecrawl's document stack is not the &lt;strong&gt;4.7 ms&lt;/strong&gt; benchmark number.&lt;/p&gt;

&lt;p&gt;It is the architecture.&lt;/p&gt;

&lt;p&gt;AnyDoc takes many document formats and funnels them into a common document model before producing one consistent Markdown representation. pdf-inspector treats PDFs as a specialized problem, classifies their pages before OCR, extracts native text when possible, and leaves the expensive cases for a separate stage.&lt;/p&gt;

&lt;p&gt;That is a much more convincing design than simply claiming to support “every document.”&lt;/p&gt;

&lt;p&gt;The benchmarks are encouraging, especially the combination of broad coverage and low conversion latency in AnyDoc, and the strong reading-order and table results in pdf-inspector. But they should still be read as benchmark snapshots, not universal performance guarantees.&lt;/p&gt;

&lt;p&gt;There are also clear boundaries.&lt;/p&gt;

&lt;p&gt;AnyDoc does not eliminate OCR.&lt;/p&gt;

&lt;p&gt;Embedded assets are retained in the document model rather than magically becoming fully reproduced Markdown.&lt;/p&gt;

&lt;p&gt;And the project has not had years to encounter the stranger documents that eventually define production parser reliability.&lt;/p&gt;

&lt;p&gt;Still, the architectural direction makes sense.&lt;/p&gt;

&lt;p&gt;The best document parser is not necessarily the one with the longest list of supported extensions or the lowest number in a benchmark table.&lt;/p&gt;

&lt;p&gt;It is the one that lets the rest of your system stop caring what kind of document arrived.&lt;/p&gt;

&lt;p&gt;That is what AnyDoc is trying to accomplish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One API for the messy input. One document model in the middle. One consistent output on the other side.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if that architecture survives the ugly documents waiting in production, Firecrawl may have built something considerably more useful than another document-to-Markdown converter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/anydoc-architecture-review-inside-firecrawl-s-rust-document-to-markdown-stack-z4k32" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>opensource</category>
      <category>developertools</category>
      <category>rust</category>
    </item>
    <item>
      <title>How Git Actually Works: A Look Inside the .git Folder</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Wed, 26 Aug 2026 05:22:19 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/how-git-actually-works-a-look-inside-the-git-folder-4fl5</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/how-git-actually-works-a-look-inside-the-git-folder-4fl5</guid>
      <description>&lt;p&gt;Most developers use Git every day and understand it as a set of commands: &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;. That's enough to get by — until it isn't, until you hit a detached HEAD, a confusing rebase conflict, or wonder why creating a new branch is instant even in a repo with 100,000 commits.&lt;/p&gt;

&lt;p&gt;The truth is that Git isn't really a version control tool with some clever commands bolted on. Underneath, it's a surprisingly simple key-value data store, and once you see that model, most of Git's "weird" behavior stops being weird.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Is a Content-Addressable Filesystem
&lt;/h2&gt;

&lt;p&gt;Strip away the commands and Git is, at its core, a system for storing content and retrieving it by the hash of that content — not by filename, not by path. Every piece of data Git tracks gets hashed (SHA-1, historically, with SHA-256 support arriving in newer versions), and that hash becomes its permanent address inside the &lt;code&gt;.git/objects&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;This one idea — content-addressable storage — explains an enormous amount of what makes Git fast, safe, and space-efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Object Types That Do Almost Everything
&lt;/h2&gt;

&lt;p&gt;Git builds its entire history out of just a few object types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blobs&lt;/strong&gt; A blob stores the raw content of a file — nothing else, no filename, no permissions, no path. Two files with identical content, even in totally different folders, produce the exact same blob and get stored only once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trees&lt;/strong&gt; A tree is Git's version of a directory listing. It maps names to other objects — blobs for files, or other trees for subdirectories — along with file modes (permissions). A tree is essentially a snapshot of a folder structure at a point in time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commits&lt;/strong&gt; A commit is a small object that points to exactly one tree (the root of the project at that moment), zero or more parent commits (none for the very first commit in a repo, more than one for a merge), and metadata: author, timestamp, and message. Notably, a commit doesn't store a diff — it stores a full snapshot reference. Git just happens to be very good at storing those snapshots efficiently through deduplication and compression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing It For Yourself
&lt;/h2&gt;

&lt;p&gt;You don't need to take this on faith — you can inspect it directly. In any Git repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello world"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; file.txt
git add file.txt
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add file"&lt;/span&gt;

&lt;span class="c"&gt;# Find the hash Git assigned to your file's content&lt;/span&gt;
git rev-parse HEAD:file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That returns &lt;code&gt;3b18e512dba79e4c8300dd08aeb37f8e728b8dad&lt;/code&gt; — a SHA-1 hash. That's not a filename; it's the address of the blob containing "hello world\n". You can go look at it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cat-file &lt;span class="nt"&gt;-p&lt;/span&gt; 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
&lt;span class="c"&gt;# hello world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can inspect any object the same way — commits, trees, and blobs are all readable with &lt;code&gt;git cat-file -p &amp;lt;hash&amp;gt;&lt;/code&gt;. Peek at your latest commit object and you'll see it's just a tree pointer, a parent pointer, and metadata — nothing more mysterious than that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where &lt;code&gt;git add&lt;/code&gt; Actually Puts Things
&lt;/h2&gt;

&lt;p&gt;There's a fourth piece we skipped: the staging area, also called the index. It's a single file at &lt;code&gt;.git/index&lt;/code&gt; that lists exactly what will go into your next commit.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;git add file.txt&lt;/code&gt;, Git doesn't touch the object database in any dramatic way — it just writes a blob for &lt;code&gt;file.txt&lt;/code&gt;'s current content, and records that blob's hash in the index alongside the filename. &lt;code&gt;git commit&lt;/code&gt; then builds a tree straight from whatever the index currently contains, not from your working directory.&lt;/p&gt;

&lt;p&gt;This explains a few things that confuse newcomers. Stage a file, then edit it again without re-staging, and &lt;code&gt;git status --short&lt;/code&gt; will show &lt;code&gt;MM&lt;/code&gt; next to it — modified in the index &lt;em&gt;and&lt;/em&gt; modified in the working directory, because the two now genuinely disagree. It's also why &lt;code&gt;git diff&lt;/code&gt; and &lt;code&gt;git diff --staged&lt;/code&gt; show different things: plain &lt;code&gt;git diff&lt;/code&gt; compares your working directory against the index, while &lt;code&gt;--staged&lt;/code&gt; compares the index against &lt;code&gt;HEAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which raises the obvious follow-up: if commits don't store diffs, how does &lt;code&gt;git diff&lt;/code&gt; produce one? By computing it on the fly. Git walks the two trees (or blobs) being compared and generates the diff in that moment. A diff in Git is a view, computed on demand — never a fact stored on disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branches Are Just Pointers
&lt;/h2&gt;

&lt;p&gt;Here's the part that changes how people think about Git: a branch is not a copy of your code. A branch is a plain text file containing a single commit hash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .git/refs/heads/main
&lt;span class="c"&gt;# 9fceb02d0ae598e95dc970b74767f19372d61af&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. That's the entire branch. When you run &lt;code&gt;git checkout -b feature&lt;/code&gt;, Git creates a new, tiny text file pointing at the same commit you're currently on. No files get copied, no history gets duplicated. That's why creating a branch in Git is instantaneous regardless of repo size — you're writing a 40-character string to a file, not cloning a project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HEAD&lt;/code&gt; works the same way, one level up: it's a pointer to whichever branch you currently have checked out (or, in a "detached HEAD" state, directly to a commit). That's the entire mystery behind detached HEAD — you've pointed &lt;code&gt;HEAD&lt;/code&gt; straight at a commit instead of at a branch, so new commits won't move any branch pointer forward. They just float, unreferenced, until something points at them again, or Git eventually garbage-collects them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Whole Picture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdkE1PwkAQhv_KOCcNW0gbTz2Y2BqiBy9SvVAO03ZKN-5Hs7sKCPx3U4qYcJw37_PMZPZY24YxxVbZTd2RC1A8lQYAIHNk6m5ZouPWzzqmxs80SVPiCqLoAfJkWWJutZYBboNjhgn05NgEmIBm72nNdyWuRlueDNBhLBwgj69gAcae8WsIimRZOOZzWIxhNhgyZasUWql4Grbhwv1VkkvFMTWap7r5d8ejOx7dKFCz0yQbTPcYOtbDVxpu6UsFFGPyQU5SpdgPndaaMCct1Q5TjKjvFUd-5wNrAZmS5vOV6sVpnlsTBJS44LVleH8pUcCbrWywAp5ZfXOQNQl4dJKUAE_GR56dbFGclizkz3BLfN9v8XgUWK1zq6zDFG82nQyMx19Q-Y94" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNpdkE1PwkAQhv_KOCcNW0gbTz2Y2BqiBy9SvVAO03ZKN-5Hs7sKCPx3U4qYcJw37_PMZPZY24YxxVbZTd2RC1A8lQYAIHNk6m5ZouPWzzqmxs80SVPiCqLoAfJkWWJutZYBboNjhgn05NgEmIBm72nNdyWuRlueDNBhLBwgj69gAcae8WsIimRZOOZzWIxhNhgyZasUWql4Grbhwv1VkkvFMTWap7r5d8ejOx7dKFCz0yQbTPcYOtbDVxpu6UsFFGPyQU5SpdgPndaaMCct1Q5TjKjvFUd-5wNrAZmS5vOV6sVpnlsTBJS44LVleH8pUcCbrWywAp5ZfXOQNQl4dJKUAE_GR56dbFGclizkz3BLfN9v8XgUWK1zq6zDFG82nQyMx19Q-Y94" alt="Mermaid Diagram" width="585" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A branch points to a commit. A commit points to a tree and its parent commit. A tree points to blobs and other trees. Everything below the branch pointer is immutable and content-addressed; only the pointer itself ever moves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merging, Rebasing, and Why History Changes
&lt;/h2&gt;

&lt;p&gt;Once you see commits as immutable, content-addressed snapshots, a few common confusions resolve themselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A merge commit&lt;/strong&gt; is just a normal commit object with two parents instead of one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rebasing rewrites history&lt;/strong&gt; because a commit's hash is derived from its content, including its parent. Change the parent, and you get a brand-new commit with a brand-new hash, even if the code is identical. This is why force-pushing after a rebase is necessary, and why rebasing shared branches causes pain: you're not editing old commits, you're creating new ones and abandoning the old ones.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fast-forward merges&lt;/strong&gt; happen when your branch pointer can simply slide forward along an existing line of commits — no new commit needed at all.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Actually Matters
&lt;/h2&gt;

&lt;p&gt;Understanding Git's object model turns a lot of "just memorize the commands" situations into things you can reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recovering "lost" commits.&lt;/strong&gt; Because objects stick around until garbage collected, &lt;code&gt;git reflog&lt;/code&gt; and &lt;code&gt;git fsck --lost-found&lt;/code&gt; can often recover commits that no branch points to anymore.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understanding&lt;/strong&gt; &lt;code&gt;.git&lt;/code&gt; &lt;strong&gt;folder size.&lt;/strong&gt; Since identical content is stored once, Git repos are often far smaller than you'd expect, even with deep history.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging confusing merge/rebase states.&lt;/strong&gt; Once you know a commit is just a snapshot plus parent pointers, conflicts stop feeling arbitrary — you can trace exactly which snapshots are being compared.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Git's command-line interface makes it look like a tool for tracking changes and diffs. Underneath, it's closer to a simple, elegant database: content-addressed objects (blobs, trees, commits) and lightweight pointers (branches, HEAD, tags) that reference them. Every confusing Git moment — a detached HEAD, a surprising rebase, an "impossible" merge conflict — gets easier to debug once you stop thinking in commands and start thinking in objects and pointers.&lt;/p&gt;

&lt;p&gt;Next time a coworker asks what a branch actually &lt;em&gt;is&lt;/em&gt;, you'll know: it's a 40-character string in a text file, pointing at a snapshot of your code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/how-git-actually-works-a-look-inside-the-git-folder-pnm2p" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>versioncontrol</category>
      <category>gitinternals</category>
      <category>commandline</category>
    </item>
    <item>
      <title>Scraping LinkedIn with Python in 2026: Profiles, Companies, and Jobs</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Tue, 25 Aug 2026 04:55:30 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/scraping-linkedin-with-python-in-2026-profiles-companies-and-jobs-b07</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/scraping-linkedin-with-python-in-2026-profiles-companies-and-jobs-b07</guid>
      <description>&lt;p&gt;LinkedIn is one of the largest publicly accessible sources of structured professional data on the web. Public profile and company pages can expose useful professional metadata, while the jobs surface provides a large, searchable source of listings. Getting that data programmatically is harder: LinkedIn uses significant anti-abuse defenses, its official APIs expose only a subset of member and platform data to most developers, and the commercial scraping landscape changed significantly after Proxycurl shut down in 2025. This guide focuses on techniques that are useful in August 2026, while treating undocumented website behavior as implementation detail rather than a stable API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;One self-contained snippet — no config, no classes. If this returns data, your environment is working. Read the rest of the guide for rate limits, proxies, and production patterns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install curl-cffi parsel
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;curl_cffi.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;parsel&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Selector&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;one_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;impersonate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chrome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept-Language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US,en;q=0.9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//script[@type=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/ld+json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;]/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getall&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@graph&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;node_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Person&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Person&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;node_type&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;one_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/in/williamhgates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Legal Takeaways
&lt;/h2&gt;

&lt;p&gt;The Ninth Circuit's April 2022 &lt;em&gt;hiQ Labs v. LinkedIn&lt;/em&gt; decision is important for scraping publicly accessible data, but it is not a blanket authorization to scrape LinkedIn. The court's CFAA analysis distinguished public websites from access that requires authentication. Other claims, including contract claims under LinkedIn's User Agreement, remain separate. See the &lt;a href="https://cdn.ca9.uscourts.gov/datastore/opinions/2022/04/18/17-16783.pdf" rel="noopener noreferrer"&gt;Ninth Circuit opinion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The hiQ Labs settlement in December 2022 included a $500,000 judgment against hiQ for contract violations, per &lt;a href="https://www.morganlewis.com/blogs/sourcingatmorganlewis/2022/12/linkedin-v-hiq-landmark-data-scraping-suit-provides-guidance-to-data-scrapers-and-web-operators" rel="noopener noreferrer"&gt;Morgan Lewis's summary&lt;/a&gt;. The hiQ case resolved both questions differently: CFAA in hiQ's favor, contract in LinkedIn's favor.&lt;/p&gt;

&lt;p&gt;LinkedIn announced legal proceedings against Proxycurl on January 24, 2025, saying the action was intended to enforce its User Agreement against unauthorized scraping and fake accounts. LinkedIn later announced on July 28, 2025 that the lawsuit had been resolved. &lt;a href="https://news.linkedin.com/2025/linkedin-takes-legal-action-to-defend-member-privacy" rel="noopener noreferrer"&gt;LinkedIn's announcement&lt;/a&gt; · &lt;a href="https://news.linkedin.com/2025/LinkedInWinsLegalBattleToProtectMemberData" rel="noopener noreferrer"&gt;LinkedIn's resolution announcement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyone reselling LinkedIn data or running a commercial-scale pipeline should talk to a lawyer before shipping.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Official API Actually Provides
&lt;/h2&gt;

&lt;p&gt;LinkedIn's current API documentation lists three open permissions available to all developers without special approval: &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;w_member_social&lt;/code&gt;. Many other products and permissions require explicit approval. For developers who need arbitrary third-party public profile data at scale, the standard self-service API does not provide an equivalent dataset. &lt;a href="https://learn.microsoft.com/en-us/linkedin/shared/authentication/getting-access" rel="noopener noreferrer"&gt;LinkedIn API access documentation&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where LinkedIn Stores Its Data
&lt;/h2&gt;

&lt;p&gt;Public profiles and company pages can expose structured data in &lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;&lt;/code&gt; tags in the initial HTML response. The exact fields vary by page, but the data can provide useful identity, organization, and other metadata without requiring JavaScript execution. Parsing structured data is often preferable to relying entirely on presentation-oriented CSS classes, but it should still be treated as observed website behavior rather than a guaranteed schema.&lt;/p&gt;

&lt;p&gt;One page can contain multiple &lt;code&gt;ld+json&lt;/code&gt; blocks. The &lt;code&gt;parse_ld_json&lt;/code&gt; helper below iterates all of them — not just the first — which matters because the &lt;code&gt;Person&lt;/code&gt; or &lt;code&gt;Organization&lt;/code&gt; node isn't always in the first block.&lt;/p&gt;

&lt;p&gt;Job search results use a different pattern. The public jobs frontend currently uses an undocumented endpoint named &lt;code&gt;jobs-guest/jobs/api/seeMoreJobPostings/search&lt;/code&gt; to request additional result pages. The response is HTML rather than a conventional JSON API. Treat this as an implementation detail: LinkedIn can change the endpoint, parameters, pagination behavior, or markup without notice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install: Why curl_cffi Instead of httpx
&lt;/h2&gt;

&lt;p&gt;Some anti-bot systems inspect TLS and HTTP fingerprints in addition to higher-level request behavior. &lt;code&gt;curl_cffi&lt;/code&gt; supports browser impersonation, which can make an HTTP client's TLS/HTTP fingerprint resemble a supported browser profile. That does not make a scraper invisible or establish how LinkedIn internally scores requests. See the &lt;a href="https://curl-cffi.readthedocs.io/en/latest/quick_start.html" rel="noopener noreferrer"&gt;curl_cffi documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;curl-cffi parsel httpx

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Keeping the fingerprint current.&lt;/strong&gt; Every code sample below uses &lt;code&gt;impersonate="chrome"&lt;/code&gt; (no version suffix). The library resolves this alias to its latest available Chrome profile — currently &lt;code&gt;chrome146&lt;/code&gt; as of August 2026 — rather than pinning you to a specific version. Since curl_cffi v0.15.1, you can also run &lt;code&gt;curl-cffi update&lt;/code&gt; after install to pull the newest fingerprint definitions without a full pip upgrade. Pinning a version like &lt;code&gt;impersonate="chrome146"&lt;/code&gt; is useful when you need reproducible fingerprints for debugging; otherwise, use the alias.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shared Helpers
&lt;/h2&gt;

&lt;p&gt;These two functions are used across every scraper below. &lt;code&gt;get_html&lt;/code&gt; handles LinkedIn's 999 soft-block with exponential back-off. &lt;code&gt;parse_ld_json&lt;/code&gt; iterates all &lt;code&gt;ld+json&lt;/code&gt; blocks on the page and returns the first node matching the requested Schema.org type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# helpers.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;curl_cffi.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;parsel&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Selector&lt;/span&gt;

&lt;span class="n"&gt;HEADERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept-Language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US,en;q=0.9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetch a URL and retry selected transient LinkedIn responses.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_ld_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return the first JSON-LD node matching node_type.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//script[@type=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/ld+json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;]/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getall&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@graph&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="n"&gt;node_type_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node_type_value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;node_type&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node_type_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;node_type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;node_type_value&lt;/span&gt;
            &lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Scraping Profiles
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;scrape_profiles&lt;/code&gt; wraps the helpers with a concurrency semaphore and an inter-request delay. The defaults are conservative starting points, not LinkedIn limits. The right values depend on the page type, network path, response behavior, and your workload. Treat rising 999 responses as a signal to reduce load and investigate rather than as a fixed quota.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# profiles.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;curl_cffi.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;helpers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_ld_json&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scrape_profiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# "http://user:pass@host:port"
&lt;/span&gt;    &lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;sem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# impersonate="chrome" tracks the latest available Chrome fingerprint.
&lt;/span&gt;    &lt;span class="c1"&gt;# Pin a version (e.g. "chrome146") only if you need reproducible fingerprints.
&lt;/span&gt;    &lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;impersonate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chrome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;sem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;html&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blocked&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_ld_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Person&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;employer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;worksFor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[{}])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/in/williamhgates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/in/satyanadella&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;scrape_profiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Adding a Residential Proxy
&lt;/h2&gt;

&lt;p&gt;A proxy can change the network path and therefore the observed IP reputation, but it is not a universal requirement and it does not solve every form of anti-abuse control. Keep proxy support configurable so you can measure whether it actually improves your workload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Residential proxy from any provider (Bright Data, Smartproxy, Oxylabs, etc.)
&lt;/span&gt;&lt;span class="n"&gt;PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://username:password@proxy-host.example.com:8080&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;scrape_profiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/in/williamhgates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PROXY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;concurrency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# lower concurrency when rotating proxies
&lt;/span&gt;        &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&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;h2&gt;
  
  
  Scraping Company Pages
&lt;/h2&gt;

&lt;p&gt;Company pages can use the same &lt;code&gt;ld+json&lt;/code&gt; approach. An &lt;code&gt;Organization&lt;/code&gt; node may expose fields such as name and description, with other attributes depending on the page. A secondary XPath pass can pick up additional fields from the DOM, but those selectors are inherently fragile. Treat structured data as a useful first layer and DOM extraction as best-effort.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# companies.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;curl_cffi.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;parsel&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Selector&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;helpers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_ld_json&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scrape_company&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# impersonate="chrome" tracks the latest available Chrome fingerprint.
&lt;/span&gt;    &lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;impersonate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chrome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;html&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="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_ld_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Organization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Best-effort: pick up extra About fields from the DOM.
&lt;/span&gt;    &lt;span class="c1"&gt;# These selectors break when LinkedIn rotates its markup — treat as supplemental.
&lt;/span&gt;    &lt;span class="n"&gt;sel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//dl[contains(@class,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;org-about&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dt/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dd//text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getall&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;

    &lt;span class="n"&gt;employees&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;numberOfEmployees&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;employee_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;employee_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;employees&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;employee_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;industry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;industry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;website&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;scrape_company&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/company/microsoft&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&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;h2&gt;
  
  
  Scraping Jobs via the Hidden API
&lt;/h2&gt;

&lt;p&gt;The jobs example uses &lt;code&gt;httpx&lt;/code&gt; because it does not depend on browser TLS impersonation. The pattern is straightforward: fetch the first search page, parse the initial cards and count, then request additional pages from the undocumented &lt;code&gt;seeMoreJobPostings&lt;/code&gt; endpoint. The sleep between pages is a conservative load-management choice, not a documented LinkedIn requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note on&lt;/strong&gt; &lt;code&gt;parse_job_cards&lt;/code&gt; &lt;strong&gt;selectors.&lt;/strong&gt; The XPath selectors below target LinkedIn's DOM structure as of August 2026. Like all DOM-based selectors, they'll break when LinkedIn updates its markup — this has happened several times in the past 18 months. If &lt;code&gt;title&lt;/code&gt; fields come back empty, inspect a raw response and update the selectors. The &lt;code&gt;ld+json&lt;/code&gt; approach used for profiles doesn't apply here because job cards on the paginated API response don't embed Schema.org nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# jobs.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;parsel&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Selector&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;

&lt;span class="n"&gt;HEADERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AppleWebKit/537.36 (KHTML, like Gecko) &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chrome/131.0.0.0 Safari/537.36&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept-Language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US,en;q=0.9&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;API_BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_job_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;sel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//li&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.//div/a/span/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.//h4/a/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.//span[@class=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;job-search-card__location&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;]/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;posted&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.//time/@datetime&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.//a/@href&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;posted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scrape_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="c1"&gt;# urlencode handles query-string encoding internally — don't pre-encode
&lt;/span&gt;    &lt;span class="c1"&gt;# values with quote_plus or you'll double-encode spaces as %2B.
&lt;/span&gt;    &lt;span class="n"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keywords&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;follow_redirects&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.linkedin.com/jobs/search?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;count_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//span[contains(@class,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;job-count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)]/text()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count_raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_job_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API_BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;start=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parse_job_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;scrape_job_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Python Developer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;United States&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What Breaks at Scale
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;impersonate="chrome"&lt;/code&gt; flag changes the TLS/HTTP fingerprint presented by the client. It is only one part of request behavior. Concurrency, timing, session state, IP/network reputation, and page type can all affect reliability, and LinkedIn can change its defenses over time.&lt;/p&gt;

&lt;p&gt;Do not build production capacity around a fixed CAPTCHA or request threshold. Measure your own success and failure rates, record response classes, and apply back-pressure when the failure rate increases.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Library Option
&lt;/h2&gt;

&lt;p&gt;If you need authenticated data — connection lists, full post engagement, private contact info — the maintained open-source option is &lt;code&gt;joeyism/linkedin_scraper&lt;/code&gt; v3.1.2 (April 2026), per &lt;a href="https://scrapfly.io/blog/posts/best-linkedin-scrapers-github" rel="noopener noreferrer"&gt;ScrapFly's August 2026 review&lt;/a&gt;. Install it with &lt;code&gt;pip install linkedin-scraper&lt;/code&gt; (not &lt;code&gt;linkedin-scraper-patchright&lt;/code&gt;, which is a separate unrelated package).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Check the license before shipping.&lt;/strong&gt; The repository's &lt;code&gt;LICENSE&lt;/code&gt; file is GPL-3.0. The README has contained conflicting license information, so inspect the actual license and the exact revision you plan to depend on rather than relying on the README alone. Whether and how GPL obligations apply to your particular product depends on how you use and distribute the code; get legal advice for a commercial product if necessary. Also test the current release against your target pages before committing to it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does scraping LinkedIn violate the CFAA?&lt;/strong&gt; The Ninth Circuit's 2022 &lt;em&gt;hiQ Labs v. LinkedIn&lt;/em&gt; decision is important because it held that the CFAA's "without authorization" concept does not apply in the same way to information on a public website that does not require authentication. That does not make scraping generally lawful: contractual and other legal issues remain separate. See the &lt;a href="https://cdn.ca9.uscourts.gov/datastore/opinions/2022/04/18/17-16783.pdf" rel="noopener noreferrer"&gt;Ninth Circuit opinion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my scraper return status 999?&lt;/strong&gt; LinkedIn can return HTTP 999 when it does not serve a request normally. Treat repeated 999 responses as an operational signal, not proof of one specific cause. Check request rate, network conditions, session behavior, and client configuration before changing one variable at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I scrape LinkedIn without an account?&lt;/strong&gt; Some public profiles, company pages, and job-search pages can be accessible without authentication, while other parts of the site require login. Availability can vary by page type and over time, so test the exact surface your application depends on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why did Proxycurl shut down?&lt;/strong&gt; LinkedIn announced legal proceedings against Proxycurl in January 2025, citing unauthorized scraping and fake accounts. LinkedIn later announced on July 28, 2025 that the lawsuit had been resolved. The episode illustrates the legal and operational risk of commercial-scale scraping infrastructure. (&lt;a href="https://news.linkedin.com/2025/linkedin-takes-legal-action-to-defend-member-privacy" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://news.linkedin.com/2025/LinkedInWinsLegalBattleToProtectMemberData" rel="noopener noreferrer"&gt;LinkedIn resolution announcement&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is&lt;/strong&gt; &lt;code&gt;linkedin-scraper&lt;/code&gt; &lt;strong&gt;v3 backward compatible with v2?&lt;/strong&gt; No. Version 3.0.0 replaced Selenium with async Playwright and switched data models to Pydantic. Pin &lt;code&gt;pip install linkedin-scraper==2.11.2&lt;/code&gt; to stay on v2 while migrating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which Chrome version should I impersonate?&lt;/strong&gt; Use &lt;code&gt;impersonate="chrome"&lt;/code&gt; when you want &lt;code&gt;curl_cffi&lt;/code&gt; to track the latest supported Chrome impersonation target. The current &lt;code&gt;curl_cffi&lt;/code&gt; documentation lists &lt;code&gt;chrome146&lt;/code&gt; as the latest available Chrome target and recommends the unversioned alias when you want the latest profile. Pin a version only when reproducibility matters. (&lt;a href="https://curl-cffi.readthedocs.io/en/latest/impersonate/targets.html" rel="noopener noreferrer"&gt;curl_cffi&lt;/a&gt;)&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/scraping-linkedin-with-python-in-2026-profiles-companies-and-jobs-n1skm" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>playwright</category>
      <category>developertools</category>
      <category>curlcffi</category>
    </item>
    <item>
      <title>The Best Open Source LLMs in August 2026: A Developer's Honest Guide</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:14:00 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/the-best-open-source-llms-in-august-2026-a-developers-honest-guide-22f8</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/the-best-open-source-llms-in-august-2026-a-developers-honest-guide-22f8</guid>
      <description>&lt;h2&gt;
  
  
  The Frontier Has No Wall
&lt;/h2&gt;

&lt;p&gt;A year ago, self-hosting an LLM for serious development work usually meant accepting an obvious quality gap versus the closed frontier.&lt;/p&gt;

&lt;p&gt;That gap is now much smaller.&lt;/p&gt;

&lt;p&gt;The best open-weight models in August 2026 are competitive with proprietary systems on a growing number of reasoning, coding, and agentic workloads. On some evaluations, they are already ahead. The more useful question for a developer is no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Which model has the highest benchmark score?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Which model fits my workload, infrastructure, cost envelope, and legal requirements?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction matters because these models make very different trade-offs.&lt;/p&gt;

&lt;p&gt;Kimi K3 pushes toward maximum capability but requires serious infrastructure. GLM-5.2 and GLM-5.3 emphasize coding and throughput. DeepSeek V4-Pro makes economics a first-class feature. MiniMax M3 is differentiated by native video and multimodality. Qwen3 remains attractive for Apache 2.0 deployments. Muse Glimmer targets local agents. Gemma 4 pushes useful multimodal capability down into smaller hardware tiers.&lt;/p&gt;

&lt;p&gt;The market is also moving fast. Kimi K3 launched in July, while &lt;a href="https://z.ai/blog/glm-5.3" rel="noopener noreferrer"&gt;GLM-5.3&lt;/a&gt;, &lt;a href="https://huggingface.co/Qwen/Qwen3.8-2.4T-A95B" rel="noopener noreferrer"&gt;Qwen3.8-Max&lt;/a&gt;, and &lt;a href="https://huggingface.co/Qwen/Qwen3.8-27B" rel="noopener noreferrer"&gt;Qwen3.8-27B&lt;/a&gt; all arrived in August before this article was published. DeepSeek changed V4 pricing during the same month (&lt;a href="https://api-docs.deepseek.com/" rel="noopener noreferrer"&gt;official API docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;So treat every benchmark and price in this article as a dated snapshot, not a permanent truth.&lt;/p&gt;

&lt;p&gt;One terminology point matters from the start: &lt;strong&gt;open-weight is not automatically the same thing as open source&lt;/strong&gt;. Public weights let you download, fine-tune, quantize, and deploy a model, but they do not necessarily expose the complete training data and reproducible training pipeline. For enterprise teams, that distinction can matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Optimize For Before You Pick
&lt;/h2&gt;

&lt;h3&gt;
  
  
  License
&lt;/h3&gt;

&lt;p&gt;Start with the license, not the leaderboard.&lt;/p&gt;

&lt;p&gt;MIT and Apache 2.0 are straightforward starting points for commercial software. Custom licenses need closer reading because they may add attribution, usage, distribution, or scale-related conditions.&lt;/p&gt;

&lt;p&gt;Kimi K3, MiniMax M3, and Qwen3.8-Max should not be treated as equivalent to a plain MIT or Apache 2.0 model simply because their weights are downloadable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment scale
&lt;/h3&gt;

&lt;p&gt;Hardware eliminates models surprisingly quickly.&lt;/p&gt;

&lt;p&gt;A cluster-scale model and a 24GB local model may both be excellent, but they solve completely different problems. Before comparing benchmark scores, decide whether you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a large multi-GPU cluster,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a smaller GPU server,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a workstation,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or a single consumer GPU / Mac.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Context
&lt;/h3&gt;

&lt;p&gt;A 1M-token context window can materially change the architecture of an application that processes large repositories, long documents, or extended agent trajectories.&lt;/p&gt;

&lt;p&gt;But context length is only useful when the model, serving stack, and workload can use it efficiently. Do not confuse a headline context number with a practical production configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modality
&lt;/h3&gt;

&lt;p&gt;If your application needs native video understanding, the shortlist changes immediately.&lt;/p&gt;

&lt;p&gt;If you only need text plus coding, several models become more attractive. If you need image or video input inside an agent loop, multimodality becomes a first-order selection criterion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost and throughput
&lt;/h3&gt;

&lt;p&gt;At scale, token price and output speed compound.&lt;/p&gt;

&lt;p&gt;A model that is slightly better but five times more expensive can be the wrong choice for a pipeline generating millions of tokens. Likewise, a cheaper model with much slower output can lose on wall-clock time when an agent makes many sequential calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick-Pick Decision Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Primary constraint&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Highest capability with public weights&lt;/td&gt;
&lt;td&gt;Kimi K3&lt;/td&gt;
&lt;td&gt;Top-tier independent composite score; strong coding profile&lt;/td&gt;
&lt;td&gt;Cluster-scale serving&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best API coding option&lt;/td&gt;
&lt;td&gt;GLM-5.3&lt;/td&gt;
&lt;td&gt;Current GLM flagship on API; strong coding focus&lt;/td&gt;
&lt;td&gt;Weights not yet available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast coding with downloadable weights&lt;/td&gt;
&lt;td&gt;GLM-5.2&lt;/td&gt;
&lt;td&gt;Strong quality + high throughput + MIT&lt;/td&gt;
&lt;td&gt;Large serving footprint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost-sensitive frontier inference&lt;/td&gt;
&lt;td&gt;DeepSeek V4-Pro-0813&lt;/td&gt;
&lt;td&gt;Strong capability at materially lower cost than many frontier APIs&lt;/td&gt;
&lt;td&gt;Slower than GLM; pricing now tiered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native video + multimodal&lt;/td&gt;
&lt;td&gt;MiniMax M3&lt;/td&gt;
&lt;td&gt;Text, image, and video in one model&lt;/td&gt;
&lt;td&gt;Custom license&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apache 2.0 large-model workhorse&lt;/td&gt;
&lt;td&gt;Qwen3 235B-A22B&lt;/td&gt;
&lt;td&gt;Strong capability/cost/licensing balance&lt;/td&gt;
&lt;td&gt;262K context; large memory footprint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local agent on consumer hardware&lt;/td&gt;
&lt;td&gt;Muse Glimmer&lt;/td&gt;
&lt;td&gt;Strong MCP/tool-oriented profile&lt;/td&gt;
&lt;td&gt;Weaker on some computer-use/terminal benchmarks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local multimodal coding&lt;/td&gt;
&lt;td&gt;Qwen3.8-27B&lt;/td&gt;
&lt;td&gt;Apache 2.0 + image/video + 27B dense model&lt;/td&gt;
&lt;td&gt;Newer ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smaller Apache 2.0 entry point&lt;/td&gt;
&lt;td&gt;Gemma 4&lt;/td&gt;
&lt;td&gt;Broad size range and strong local ecosystem&lt;/td&gt;
&lt;td&gt;Not frontier-class&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Frontier Benchmark Snapshot
&lt;/h2&gt;

&lt;p&gt;Artificial Analysis scores are useful here because they provide a consistent cross-model evaluation framework. They should still be read as one signal rather than a universal definition of intelligence.&lt;/p&gt;

&lt;p&gt;For the current August snapshot, the important story is the cluster at the top:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Intelligence Index&lt;/th&gt;
&lt;th&gt;Practical read&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kimi K3&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;Top weights-available option&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLM-5.3&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;Tied with K3 on the API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.8 2.4T-A95B&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;High-end Qwen frontier contender&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4-Pro-0813&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;Stronger than its preview release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.8-27B&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;Exceptional size/performance position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLM-5.2&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;Still highly competitive on coding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MiniMax M3&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;More differentiated by modality than raw text score&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point is not that 60 is “good” and 52 is “bad.” A 52-score model that fits on your hardware can be more valuable than a 60-score model that needs an accelerator cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kimi K3: The Benchmark Leader
&lt;/h2&gt;

&lt;p&gt;Kimi K3 is the clearest choice when the question is simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What is the strongest open-weight model I can actually download today?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a 2.8T-parameter sparse MoE with 16 of 896 routed experts active per token, a 1M-token context window, and a public checkpoint released under a custom Kimi K3 license.&lt;/p&gt;

&lt;p&gt;Its architecture combines &lt;strong&gt;Kimi Delta Attention (KDA)&lt;/strong&gt;, &lt;strong&gt;Stable LatentMoE&lt;/strong&gt;, and &lt;strong&gt;Attention Residuals&lt;/strong&gt;. KDA is particularly important for long-context efficiency because it combines linear and full-attention patterns rather than treating every layer identically.&lt;/p&gt;

&lt;p&gt;Moonshot's &lt;a href="https://github.com/MoonshotAI/Kimi-K3" rel="noopener noreferrer"&gt;current Kimi K3 repository&lt;/a&gt; reports &lt;strong&gt;88.3 on Terminal-Bench 2.1&lt;/strong&gt;, alongside strong results on FrontierSWE, DeepSWE, ProgramBench, and GPQA Diamond. Artificial Analysis also places K3 at the top of its open-weight Intelligence Index snapshot at 60.&lt;/p&gt;

&lt;p&gt;That does not mean K3 wins every benchmark. It does not. The most important example is SWE-Bench Verified, where DeepSeek's published score is higher. Benchmark harness differences also matter, especially on coding-agent evaluations.&lt;/p&gt;

&lt;p&gt;The bigger practical problem is infrastructure.&lt;/p&gt;

&lt;p&gt;The official K3 checkpoint is around &lt;strong&gt;1.56 TB&lt;/strong&gt;. This is not a model you casually start on an eight-GPU box. Moonshot's serving guidance points toward large accelerator configurations, and production deployment is a cluster problem.&lt;/p&gt;

&lt;p&gt;The other consideration is the license. K3 is &lt;strong&gt;not MIT&lt;/strong&gt; and &lt;strong&gt;not Apache 2.0&lt;/strong&gt;. It uses a custom license with additional terms at very large commercial scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Kimi K3 when:&lt;/strong&gt; capability matters more than infrastructure simplicity, you can afford cluster-scale inference, and you want the strongest downloadable model in this comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  GLM-5.2 / GLM-5.3: The Production Coding Workhorse
&lt;/h2&gt;

&lt;p&gt;The GLM family is interesting because it separates two different needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GLM-5.2&lt;/strong&gt; is the practical weights-available option. &lt;strong&gt;GLM-5.3&lt;/strong&gt; is the newer API flagship.&lt;/p&gt;

&lt;p&gt;GLM-5.2 is a roughly 744B-parameter sparse MoE with about 40B active parameters per token and a 1M-token context. It is released under MIT and has built a strong reputation among coding-agent users.&lt;/p&gt;

&lt;p&gt;Its Artificial Analysis Intelligence Index score is 51. Z.ai reports &lt;strong&gt;62.1% on SWE-Bench Pro&lt;/strong&gt; and an output speed around &lt;strong&gt;168–200 tokens/second&lt;/strong&gt;. The exact throughput number should be treated as measurement-dependent, but the high-throughput positioning is real and important.&lt;/p&gt;

&lt;p&gt;GLM-5.3 changes the equation for teams that do not require public weights. Released in August, it is the current GLM API model and reaches an Artificial Analysis score of &lt;strong&gt;60&lt;/strong&gt;, tying Kimi K3 in the August snapshot.&lt;/p&gt;

&lt;p&gt;For coding agents, that makes GLM-5.3 especially interesting: you get the newer model without having to operate the enormous checkpoint yourself.&lt;/p&gt;

&lt;p&gt;The trade-off is obvious. GLM-5.3's weights were not yet public as of the article's publication date, so it should not be described as equivalent to K3 from a self-hosting perspective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use GLM-5.2 when:&lt;/strong&gt; you want a strong coding model with public weights, MIT licensing, and high throughput.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use GLM-5.3 when:&lt;/strong&gt; API access is acceptable and you want the current GLM capability level without running the model yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  DeepSeek V4-Pro: The Cost-Sensitive Frontier Choice
&lt;/h2&gt;

&lt;p&gt;DeepSeek V4-Pro is the model to watch when economics matter as much as benchmark position.&lt;/p&gt;

&lt;p&gt;The original preview launched in April. The important August event is the &lt;strong&gt;V4-Pro-0813 GA release&lt;/strong&gt;, which improved the model's Artificial Analysis score from the earlier preview level to &lt;strong&gt;53&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The model is a 1.6T sparse MoE with about 49B active parameters, a 1M-token context window, and MIT licensing. It is text-only rather than multimodal.&lt;/p&gt;

&lt;p&gt;The most important change for production planning is pricing.&lt;/p&gt;

&lt;p&gt;The old flat &lt;strong&gt;$0.87/M output-token&lt;/strong&gt; figure is no longer current. DeepSeek moved V4-Pro to peak/off-peak pricing on August 16. That means any article comparing DeepSeek's economics using the old flat rate is already stale.&lt;/p&gt;

&lt;p&gt;The good news is that V4-Pro remains highly competitive on cost, especially for workloads that can take advantage of lower off-peak rates.&lt;/p&gt;

&lt;p&gt;The downside is throughput. Artificial Analysis measures the GA release at roughly &lt;strong&gt;77 tokens/second&lt;/strong&gt;, below the GLM family.&lt;/p&gt;

&lt;p&gt;For batch generation, classification, summarization, and structured generation, that can be a very attractive trade. For latency-sensitive multi-step agent loops, the economics may not be the only consideration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use DeepSeek V4-Pro when:&lt;/strong&gt; cost per generated token is one of your primary constraints and your workloads can tolerate its lower throughput or take advantage of off-peak pricing.&lt;/p&gt;




&lt;h2&gt;
  
  
  MiniMax M3: The Multimodal Specialist
&lt;/h2&gt;

&lt;p&gt;MiniMax M3 earns its place because it optimizes for something the other frontier models do not prioritize as strongly: &lt;strong&gt;native multimodal reasoning that includes video&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;M3 is a sparse MoE model with roughly 428B total parameters and around 23B active parameters per token. Its documented context is &lt;strong&gt;1M tokens&lt;/strong&gt;, with 512K functioning as an important guaranteed/billing threshold.&lt;/p&gt;

&lt;p&gt;It accepts &lt;strong&gt;text, image, and video input&lt;/strong&gt;. That makes it particularly interesting for applications that need to reason across screenshots, documents, images, and video frames without building separate modality pipelines.&lt;/p&gt;

&lt;p&gt;Artificial Analysis currently places M3 at 45 on its Intelligence Index, while its output speed is around 105 tokens/second.&lt;/p&gt;

&lt;p&gt;The important caveat is licensing. MiniMax uses its &lt;strong&gt;Community License&lt;/strong&gt;, not MIT or Apache 2.0. Commercial deployment therefore deserves a license review before you build around the model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use MiniMax M3 when:&lt;/strong&gt; video and multimodal reasoning are core requirements rather than nice-to-have features.&lt;/p&gt;




&lt;h2&gt;
  
  
  Qwen3 235B-A22B: The Apache Workhorse
&lt;/h2&gt;

&lt;p&gt;Qwen3 235B-A22B remains one of the most practical large open models for teams that care about licensing and self-hosting.&lt;/p&gt;

&lt;p&gt;It is a 235B sparse MoE with 22B active parameters per token, a 262K context window, and an &lt;strong&gt;Apache 2.0&lt;/strong&gt; license.&lt;/p&gt;

&lt;p&gt;Its appeal is not that it beats every frontier model. It is that the combination of capability, licensing, API economics, and deployment flexibility is unusually balanced.&lt;/p&gt;

&lt;p&gt;With INT4 quantization, the model can fit into a roughly 60GB-class VRAM budget, making it much more approachable than cluster-scale frontier checkpoints.&lt;/p&gt;

&lt;p&gt;The important distinction is that &lt;strong&gt;Qwen3 235B and Qwen3.8 are separate model families&lt;/strong&gt;. Qwen3.8 is newer and much larger at the top end, but the 235B model remains attractive when you specifically want a mature Apache 2.0 workhorse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Qwen3 235B when:&lt;/strong&gt; Apache 2.0 matters, you want a large model you can actually deploy yourself, and you do not need the 1M-token context of the newest frontier systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Muse Glimmer: The Local Agent
&lt;/h2&gt;

&lt;p&gt;Muse Glimmer answers a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What capable agent model can I actually run on hardware I own?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meta's Glimmer is a roughly 30B-class dense model with a 131K context window and Apache 2.0 licensing. It accepts text and image inputs and is designed specifically around agentic workflows and tool use.&lt;/p&gt;

&lt;p&gt;Its strongest published results are on agent-oriented evaluations such as MCP Atlas and DeepSearch QA. Meta's own comparison tables also show areas where Qwen3.6-27B performs better, particularly on some computer-use and terminal evaluations.&lt;/p&gt;

&lt;p&gt;That is actually useful because it tells you what Glimmer is &lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Glimmer's most interesting advantage is not being a universal benchmark winner. It is providing a capable local agent stack without requiring a giant cluster.&lt;/p&gt;

&lt;p&gt;Quantized builds can fit into a roughly 24GB-class GPU envelope, depending on the quantization and serving configuration. The model also has broad local-runtime support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Muse Glimmer when:&lt;/strong&gt; privacy, local execution, and MCP/tool orchestration matter more than absolute benchmark leadership.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gemma 4: The Entry Point
&lt;/h2&gt;

&lt;p&gt;Gemma 4 is not a frontier contender against Kimi K3 or GLM-5.3, and it does not need to be.&lt;/p&gt;

&lt;p&gt;Its strength is breadth.&lt;/p&gt;

&lt;p&gt;Google's family includes &lt;strong&gt;E2B, E4B, 12B Unified, 26B A4B MoE, and 31B Dense&lt;/strong&gt; variants, with Apache 2.0 licensing. The edge models offer 128K context, while the larger models support up to 256K.&lt;/p&gt;

&lt;p&gt;The family is multimodal, and the smaller variants extend into audio as well. That makes Gemma unusually flexible across edge, workstation, and larger local deployments.&lt;/p&gt;

&lt;p&gt;For developers getting started with self-hosted inference, the combination of a clean license, multiple model sizes, multimodal capability, and a large ecosystem is compelling.&lt;/p&gt;

&lt;p&gt;One hardware caveat is important: consumer-GPU deployment depends heavily on quantization and context length. A 31B model that fits on a 24GB card in one 4-bit configuration is not the same thing as saying every serving configuration fits into 24GB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Gemma 4 when:&lt;/strong&gt; you are getting started with local inference, need a smaller model family, want Apache 2.0, or want a mature ecosystem across several hardware tiers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three August Releases You Should Not Ignore
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Qwen3.8-Max
&lt;/h3&gt;

&lt;p&gt;Qwen3.8-Max is the most important omitted model from the original draft because it moves the Qwen family into the same conversation as the largest frontier open-weight systems.&lt;/p&gt;

&lt;p&gt;The open checkpoint is around &lt;strong&gt;2.4T parameters with roughly 95B active&lt;/strong&gt;, while the hosted version provides multimodal capabilities and a 1M-token context configuration.&lt;/p&gt;

&lt;p&gt;The key caveat is that the &lt;strong&gt;hosted API and downloadable checkpoint are not identical product experiences&lt;/strong&gt;. The public checkpoint has different modality/context characteristics and uses a custom Qwen3.8-Max license.&lt;/p&gt;

&lt;p&gt;At this scale, the open weights are a datacenter project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why watch it:&lt;/strong&gt; frontier capability without being tied to a closed model API, for organizations with the infrastructure to serve it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qwen3.8-27B
&lt;/h3&gt;

&lt;p&gt;Qwen3.8-27B is much more relevant to ordinary developers.&lt;/p&gt;

&lt;p&gt;It is a dense &lt;strong&gt;27.78B&lt;/strong&gt; model under &lt;strong&gt;Apache 2.0&lt;/strong&gt;, with native multimodal input and a 262K context window, extendable with long-context techniques.&lt;/p&gt;

&lt;p&gt;Quantized builds can fit into a roughly 17GB-class memory envelope, putting it firmly into single-GPU territory.&lt;/p&gt;

&lt;p&gt;It is especially interesting because it fills the exact hole created by the original article's nonexistent “Gemma 4 27B” recommendation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why watch it:&lt;/strong&gt; Apache 2.0, multimodality, and serious capability in a model that is still realistic to run locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  GLM-5.3
&lt;/h3&gt;

&lt;p&gt;GLM-5.3 deserves mention even though its weights were not yet public at publication.&lt;/p&gt;

&lt;p&gt;Its Artificial Analysis score of &lt;strong&gt;60&lt;/strong&gt; puts it alongside Kimi K3 in the August snapshot, and its coding-focused positioning makes it one of the most important API models to test if your workload is agentic software engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why watch it:&lt;/strong&gt; it changes the conclusion for teams that value API performance more than self-hosting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open-Weight vs. Open-Source
&lt;/h2&gt;

&lt;p&gt;This distinction is easy to ignore until it becomes important.&lt;/p&gt;

&lt;p&gt;An open-weight model gives you the model parameters. That can be enough for fine-tuning, local inference, quantization, private deployment, and serious product development.&lt;/p&gt;

&lt;p&gt;But it does not necessarily give you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the complete training dataset,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the full preprocessing pipeline,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the exact training recipe,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;or the ability to reproduce the model from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters differently depending on the organization.&lt;/p&gt;

&lt;p&gt;For a startup shipping an internal coding assistant, it may be mostly academic.&lt;/p&gt;

&lt;p&gt;For a regulated enterprise, a research lab, or a company planning to maintain a model for years, it can affect reproducibility, legal review, procurement, and long-term risk.&lt;/p&gt;

&lt;p&gt;Also read the actual license. “Open weights” does not imply MIT or Apache 2.0.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;The open-weight ecosystem has moved from “good enough if you accept compromises” to “choose according to your constraints.”&lt;/p&gt;

&lt;p&gt;That changes how you should evaluate models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need the strongest downloadable frontier model?&lt;/strong&gt; Start with &lt;strong&gt;Kimi K3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need the strongest current coding API in this group?&lt;/strong&gt; Test &lt;strong&gt;GLM-5.3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need high-throughput coding with public weights?&lt;/strong&gt; &lt;strong&gt;GLM-5.2&lt;/strong&gt; remains compelling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need cost-sensitive frontier inference?&lt;/strong&gt; &lt;strong&gt;DeepSeek V4-Pro-0813&lt;/strong&gt; remains one of the strongest economic choices, but use current tiered pricing in your model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need native video understanding?&lt;/strong&gt; &lt;strong&gt;MiniMax M3&lt;/strong&gt; is the specialist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need Apache 2.0 and a large self-hosted model?&lt;/strong&gt; &lt;strong&gt;Qwen3 235B-A22B&lt;/strong&gt; remains highly attractive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need a local agent on consumer hardware?&lt;/strong&gt; Evaluate &lt;strong&gt;Muse Glimmer&lt;/strong&gt; and &lt;strong&gt;Qwen3.8-27B&lt;/strong&gt; against your exact workload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need an approachable local family with a clean license?&lt;/strong&gt; &lt;strong&gt;Gemma 4&lt;/strong&gt; is still one of the best starting points.&lt;/p&gt;

&lt;p&gt;The leaderboard will change again next week.&lt;/p&gt;

&lt;p&gt;Your hardware budget, latency target, license requirements, and workload will not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://artificialanalysis.ai/" rel="noopener noreferrer"&gt;Artificial Analysis — Intelligence Index&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/MoonshotAI/Kimi-K3" rel="noopener noreferrer"&gt;Moonshot AI — Kimi K3 GitHub repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/MoonshotAI/Kimi-K3/blob/main/LICENSE" rel="noopener noreferrer"&gt;Moonshot AI — Kimi K3 license&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://z.ai/blog/glm-5.3" rel="noopener noreferrer"&gt;Z.ai — GLM-5.3 announcement&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/zai-org/GLM-5.2" rel="noopener noreferrer"&gt;Hugging Face — GLM-5.2&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://api-docs.deepseek.com/" rel="noopener noreferrer"&gt;DeepSeek — API documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.minimax.io/models/text/m3" rel="noopener noreferrer"&gt;MiniMax — M3 model page&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.minimax.io/blog/minimax-m3" rel="noopener noreferrer"&gt;MiniMax — M3 technical/release post&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507" rel="noopener noreferrer"&gt;Hugging Face — Qwen3-235B-A22B-Instruct-2507&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/Qwen/Qwen3.8-2.4T-A95B" rel="noopener noreferrer"&gt;Hugging Face — Qwen3.8-2.4T-A95B&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/Qwen/Qwen3.8-27B" rel="noopener noreferrer"&gt;Hugging Face — Qwen3.8-27B&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/meta-models/Muse-Glimmer-30B" rel="noopener noreferrer"&gt;Hugging Face — Muse Glimmer 30B&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/gemma-4/" rel="noopener noreferrer"&gt;Google DeepMind — Gemma 4&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/the-best-open-source-llms-in-august-2026-a-developer-s-honest-guide-ktrmx" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>aimodels</category>
      <category>opensourcemodels</category>
      <category>benchmarks</category>
      <category>opensourcemodelsaugust2026</category>
    </item>
    <item>
      <title>Caching Strategies Every Backend Developer Must Know</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Fri, 21 Aug 2026 07:10:14 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/caching-strategies-every-backend-developer-must-know-1588</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/caching-strategies-every-backend-developer-must-know-1588</guid>
      <description>&lt;p&gt;There is a reason Phil Karlton's 1990s quip — that the two hardest problems in computer science are cache invalidation and naming things — still surfaces in every engineering conversation. Caching is simple in theory and genuinely difficult in practice. Get it right and your API responds in single-digit milliseconds under load. Get it wrong and you ship corrupted data, stale reads, or a cache stampede that takes down your database at peak traffic.&lt;/p&gt;

&lt;p&gt;This guide cuts through the noise. You will learn the five core caching patterns, when to reach for each one, how eviction policies work, how to approach the invalidation problem, and what &lt;em&gt;not&lt;/em&gt; to cache. Every section includes working code you can apply today.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Caching Matters: The Numbers
&lt;/h2&gt;

&lt;p&gt;The performance gap between a database read and a cache read is not incremental — it is categorical. AWS benchmarks on RDS for MySQL 8.0 paired with ElastiCache &lt;a href="https://aws.amazon.com/blogs/database/optimize-cost-and-boost-performance-of-rds-for-mysql-using-amazon-elasticache-for-redis/" rel="noopener noreferrer"&gt;show average read latency dropping from 14 ms to 0.51 ms&lt;/a&gt; — a 27x improvement — with RDS CPU utilization falling from 78% to 32% and throughput increasing 34% simultaneously. A single Redis instance, per &lt;a href="https://redis.io/docs/latest/operate/oss_and_stack/management/optimization/benchmarks/" rel="noopener noreferrer"&gt;Redis's own benchmark documentation&lt;/a&gt;, can sustain over 1.8 million GET operations per second with pipelining enabled. The database cannot compete with RAM on raw throughput.&lt;/p&gt;

&lt;p&gt;The impact at scale is equally stark. Facebook's Memcached deployment, &lt;a href="https://www.usenix.org/conference/nsdi13/technical-sessions/presentation/nishtala" rel="noopener noreferrer"&gt;documented at USENIX NSDI '13&lt;/a&gt;, handles billions of requests per second across trillions of cached items — an architecture where the cache, not the database, is the primary read path for the world's largest social network. &lt;a href="https://pages.awscloud.com/Optimize-Amazon-RDS-and-Aurora-Costs-with-ElastiCache-for-Redis_2023_SN-0701-DAT_OD" rel="noopener noreferrer"&gt;AWS benchmarks&lt;/a&gt; further show caching RDS workloads can reduce infrastructure costs by up to 55%, because fewer read replicas are needed.&lt;/p&gt;

&lt;p&gt;The relationship between hit rate and database load is direct: at an 80% cache hit rate, 80% of your database reads are eliminated. The chart below shows how this scales:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2n07wrpzko9xiwctal2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff2n07wrpzko9xiwctal2.webp" width="720" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The point is not that caching always helps — the sections below explain when it actively hurts. It is that ignoring it, at any meaningful scale, almost always leaves significant performance and cost on the table.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Terminology
&lt;/h2&gt;

&lt;p&gt;Get these four concepts locked in before the patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache hit / cache miss&lt;/strong&gt; — A &lt;em&gt;hit&lt;/em&gt; means the requested key exists in cache and is returned directly. A &lt;em&gt;miss&lt;/em&gt; means it does not; the application must fetch from the source of truth (usually the database).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TTL (Time to Live)&lt;/strong&gt; — How long a cached entry lives before it expires automatically. Too short and you get high miss rates; too long and you risk serving stale data. The right TTL is almost always workload-specific and discovered through measurement, not intuition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eviction policy&lt;/strong&gt; — What happens when the cache runs out of memory. The cache must remove &lt;em&gt;something&lt;/em&gt; to make room. Your policy choice determines &lt;em&gt;what&lt;/em&gt; gets removed (covered in its own section below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache stampede (thundering herd)&lt;/strong&gt; — What happens when many requests simultaneously miss a key that just expired, all racing to repopulate it from the database at once. This is one of the most common ways caching makes an outage &lt;em&gt;worse&lt;/em&gt; rather than better.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Decision Framework
&lt;/h2&gt;

&lt;p&gt;Before the deep dives, here is the pattern-selection map. Jump to whichever section applies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Is&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;frequently&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;written&lt;/span&gt; &lt;span class="n"&gt;infrequently&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;Aside&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Through&lt;/span&gt;

&lt;span class="n"&gt;Is&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;consistency&lt;/span&gt; &lt;span class="n"&gt;critical&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Through&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;No&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;writes&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;very&lt;/span&gt; &lt;span class="n"&gt;frequent&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;Behind&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;durable&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Are&lt;/span&gt; &lt;span class="n"&gt;hot&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="n"&gt;causing&lt;/span&gt; &lt;span class="n"&gt;stampedes&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Refresh&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Ahead&lt;/span&gt;

&lt;span class="n"&gt;Can&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;tolerate&lt;/span&gt; &lt;span class="n"&gt;eventual&lt;/span&gt; &lt;span class="nf"&gt;consistency&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;TTL&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;based&lt;/span&gt; &lt;span class="n"&gt;invalidation&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;sufficient&lt;/span&gt;

&lt;span class="n"&gt;Must&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;latest&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="n"&gt;immediately&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Do&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Five Core Caching Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Cache-Aside (Lazy Loading)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The most common pattern.&lt;/strong&gt; The application owns all cache interaction logic. On a read, it checks the cache first. On a miss, it queries the database, stores the result in cache, and returns it to the caller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;▼&lt;/span&gt;
  &lt;span class="nc"&gt;Cache&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="err"&gt;──&lt;/span&gt;&lt;span class="nc"&gt;Yes&lt;/span&gt;&lt;span class="err"&gt;──▶&lt;/span&gt; &lt;span class="k"&gt;Return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="nc"&gt;No&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;▼&lt;/span&gt;
  &lt;span class="nc"&gt;Query&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;▼&lt;/span&gt;
  &lt;span class="nc"&gt;Store&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="no"&gt;TTL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;▼&lt;/span&gt;
  &lt;span class="k"&gt;Return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Node.js / Redis example:&lt;/strong&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&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;redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Check cache first&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&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;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// cache hit&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Miss — fetch from database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Populate cache with a 10-minute TTL&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&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;&lt;strong&gt;Python equivalent:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDIS_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE id = %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,)).&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; Read-heavy workloads where data changes infrequently. The cache only populates on demand, so you never pre-warm stale entries. It is resilient to cache failures — if Redis goes down, the application still works (slower, but correctly).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; The first request after a cache miss (or expiry) always hits the database. Under high concurrency this becomes the stampede problem. Add a distributed lock or use the refresh-ahead pattern to mitigate.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Read-Through
&lt;/h3&gt;

&lt;p&gt;Similar to cache-aside, but the &lt;strong&gt;cache itself fetches from the database&lt;/strong&gt; on a miss, rather than the application. The application &lt;em&gt;only ever talks to the cache&lt;/em&gt;.&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="c1"&gt;// The cache client is configured with a loader function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CacheClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Application code is now clean:&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// miss handled internally&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; When you want to keep cache interaction logic in one place and out of business code. Works well with managed caching services that support loader callbacks (e.g., Momento, AWS ElastiCache with data tiering).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; Slightly less flexible than cache-aside — you cannot customize the miss flow per call site. The first-request miss penalty is identical.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Write-Through
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Every write goes to the cache &lt;em&gt;and&lt;/em&gt; the database simultaneously&lt;/strong&gt;, synchronously, before returning to the caller.&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Write to database first (or transactionally with cache)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;'&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;name&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Immediately update cache&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;updated&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;&lt;strong&gt;When to use it:&lt;/strong&gt; When data consistency is critical and writes are not extremely frequent. The cache is always warm and always fresh. Read performance is excellent because entries exist immediately after a write — no cold-start miss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; Every write requires two round-trips (database + cache) before returning. For write-heavy workloads this compounds at scale. You also cache data that might never be read, wasting memory.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Write-Behind (Write-Back)
&lt;/h3&gt;

&lt;p&gt;The application writes &lt;strong&gt;to the cache only&lt;/strong&gt;, and a background process flushes dirty entries to the database asynchronously. The write returns immediately after the cache is updated.&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="c1"&gt;// Simplified write-behind with a queue&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Write to cache immediately — caller gets fast response&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="c1"&gt;// Queue the database write for background processing&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lPush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;db:write-queue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&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="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Background worker (runs separately)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processWriteQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while &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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;brPop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;db:write-queue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// blocking pop&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;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`UPDATE &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; SET name=$1, email=$2 WHERE id=$3`&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;name&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;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&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;&lt;strong&gt;When to use it:&lt;/strong&gt; High write-throughput scenarios where sub-millisecond write latency is required and you can tolerate a small window of data loss. Session stores, analytics event pipelines, activity feeds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; &lt;strong&gt;Risk of data loss.&lt;/strong&gt; If the cache node fails between the write and the flush, the database never gets updated. Always pair write-behind with Redis persistence (AOF or RDB) and durable queue infrastructure (e.g., Kafka, SQS) in production.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Refresh-Ahead (Proactive Refresh)
&lt;/h3&gt;

&lt;p&gt;The cache &lt;strong&gt;predicts which entries are about to expire&lt;/strong&gt; and refreshes them in the background &lt;em&gt;before&lt;/em&gt; they go cold — so the caller never experiences a miss.&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="nx"&gt;REFRESH_THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// refresh when 20% of TTL remains&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserWithRefreshAhead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;cached&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttlRemaining&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;),&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;cached&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="nx"&gt;fullTtl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// your configured TTL&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldRefresh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ttlRemaining&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;fullTtl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;REFRESH_THRESHOLD&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;shouldRefresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Trigger background refresh without blocking the caller&lt;/span&gt;
      &lt;span class="nf"&gt;refreshUserCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Full miss — blocking refresh&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;refreshUserCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;refreshUserCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&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;&lt;strong&gt;When to use it:&lt;/strong&gt; Frequently accessed, expensive-to-compute data where cache miss latency is unacceptable. Home page aggregations, pricing data, leaderboards. Eliminates the stampede problem entirely for hot keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; You may refresh data that was never requested after its refresh — wasted compute. Requires good observability to tune the threshold correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Eviction Policies: What Gets Dropped When Memory Is Full
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;Full Name&lt;/th&gt;
&lt;th&gt;How It Works&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LRU&lt;/td&gt;
&lt;td&gt;Least Recently Used&lt;/td&gt;
&lt;td&gt;Evicts the entry accessed least recently&lt;/td&gt;
&lt;td&gt;General-purpose; good default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LFU&lt;/td&gt;
&lt;td&gt;Least Frequently Used&lt;/td&gt;
&lt;td&gt;Evicts the entry accessed least often overall&lt;/td&gt;
&lt;td&gt;Workloads with stable hot-key distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FIFO&lt;/td&gt;
&lt;td&gt;First In First Out&lt;/td&gt;
&lt;td&gt;Evicts oldest entry regardless of access&lt;/td&gt;
&lt;td&gt;Simple queues; less common&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTL&lt;/td&gt;
&lt;td&gt;Time-based&lt;/td&gt;
&lt;td&gt;Evicts based on expiry time&lt;/td&gt;
&lt;td&gt;All workloads; complements LRU/LFU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Evicts a random entry&lt;/td&gt;
&lt;td&gt;Rarely the right choice in production&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Redis default is&lt;/strong&gt; &lt;code&gt;noeviction&lt;/code&gt; — it throws an error when memory is full rather than silently dropping data. Switch to &lt;code&gt;allkeys-lru&lt;/code&gt; for most production workloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In redis.conf or via CONFIG SET&lt;/span&gt;
maxmemory 2gb
maxmemory-policy allkeys-lru

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For workloads with clear hot-key skew (e.g., celebrity social media posts), &lt;code&gt;allkeys-lfu&lt;/code&gt; tends to outperform LRU because frequency is a better predictor of future access than recency. &lt;a href="https://www.usenix.org/system/files/conference/nsdi18/nsdi18-beckmann.pdf" rel="noopener noreferrer"&gt;USENIX NSDI '18 research&lt;/a&gt; shows that hit rate increases logarithmically as a function of cache capacity — meaning the eviction policy becomes &lt;em&gt;more&lt;/em&gt; important than raw memory size as you scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cache Invalidation: The Hard Part
&lt;/h2&gt;

&lt;p&gt;Phil Karlton was right. Cache invalidation is hard because &lt;strong&gt;the cache and the source of truth can diverge&lt;/strong&gt;, and the application must detect and resolve that divergence without serving incorrect data or generating excessive database load.&lt;/p&gt;

&lt;p&gt;The three practical strategies:&lt;/p&gt;

&lt;h3&gt;
  
  
  TTL-based expiry
&lt;/h3&gt;

&lt;p&gt;Let entries expire automatically after a configured duration. Simple, predictable, eventually consistent.&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product:123:price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 5 min&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Risk:&lt;/strong&gt; Stale reads for up to the full TTL window. For pricing data, a 5-minute stale price may be acceptable. For account balances, it is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-driven invalidation
&lt;/h3&gt;

&lt;p&gt;Invalidate (delete) a cache entry the moment the underlying data changes, rather than waiting for TTL expiry.&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="c1"&gt;// In your update endpoint&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE products SET price = $1 WHERE id = $2&lt;/span&gt;&lt;span class="dl"&gt;'&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;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Immediately purge — next read will miss and repopulate&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:price`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Or pattern-delete all keys related to this product&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:*`&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;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&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;&lt;strong&gt;Risk:&lt;/strong&gt; Delete-before-repopulate creates a brief window where all in-flight requests hit the database simultaneously. For high-traffic keys, use cache-aside with a distributed lock, or write-through instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versioned keys
&lt;/h3&gt;

&lt;p&gt;Append a version number or hash to the cache key. Updates increment the version, making the old key unreachable without requiring an explicit delete.&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="c1"&gt;// Store the current version&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product:123:version&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;v5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Cache key includes version&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product:123:version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`product:123:price:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// On update: bump version (old key becomes unreachable)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product:123:version&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;This is the safest approach for multi-region or distributed caches where explicit delete propagation is unreliable. Old entries age out via TTL naturally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Redis vs. Memcached: Which One?
&lt;/h2&gt;

&lt;p&gt;This question comes up in every architecture discussion. The short answer for new projects: &lt;strong&gt;use Redis&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Redis&lt;/th&gt;
&lt;th&gt;Memcached&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data types&lt;/td&gt;
&lt;td&gt;Strings, hashes, lists, sets, sorted sets, streams&lt;/td&gt;
&lt;td&gt;Strings only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence&lt;/td&gt;
&lt;td&gt;RDB snapshots + AOF log&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication&lt;/td&gt;
&lt;td&gt;Built-in primary/replica&lt;/td&gt;
&lt;td&gt;External only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pub/Sub&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lua scripting&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max value size&lt;/td&gt;
&lt;td&gt;512 MB&lt;/td&gt;
&lt;td&gt;1 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multithreading&lt;/td&gt;
&lt;td&gt;Multi-threaded I/O (Redis 6+)&lt;/td&gt;
&lt;td&gt;Multi-threaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Nearly all production use cases&lt;/td&gt;
&lt;td&gt;Pure key/value, ultra-simple workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Memcached's one genuine advantage is slightly lower memory overhead for pure string storage at extreme scale. Unless you are operating at hundreds of terabytes of cache data, this rarely matters. Redis's richer data types, persistence options, and Lua scripting make it the clear default.&lt;/p&gt;

&lt;p&gt;The benchmark comparison below is from real AWS infrastructure measurements — not synthetic lab tests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4o4albedx8350dmi172w.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4o4albedx8350dmi172w.webp" width="720" height="380"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What NOT to Cache
&lt;/h2&gt;

&lt;p&gt;Caching is not universally beneficial. These are situations where it actively causes harm:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Highly volatile data.&lt;/strong&gt; If a value changes more often than your TTL, you will serve stale data constantly while paying cache infrastructure overhead for essentially no hits. Financial ticker prices and live sports scores are common examples where a direct database or streaming feed is the right answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unbounded key spaces.&lt;/strong&gt; If your cache key includes a user-supplied parameter with high cardinality (e.g., search query strings), you will generate millions of cache keys that each get accessed once. This consumes memory, produces near-zero hit rates, and degrades eviction efficiency. Apply caching only to keys with stable, bounded spaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data that is cheaper to recompute than to cache.&lt;/strong&gt; Simple arithmetic or deterministic in-memory transformations have effectively zero cost. Routing them through a network call to Redis adds latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data requiring real-time consistency.&lt;/strong&gt; If the application contract requires that every read reflects every write with zero lag — shopping cart totals, bank balances, inventory counts during flash sales — a cache introduces a consistency lag that your users will experience as bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Personally identifiable information you do not need to cache.&lt;/strong&gt; Every cached PII record is an additional attack surface. If the TTL benefits do not justify the exposure, leave it out of the cache.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preventing the Cache Stampede
&lt;/h2&gt;

&lt;p&gt;When a hot key expires under heavy traffic, every concurrent request races to repopulate it. This is the stampede. Three proven defenses:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Probabilistic early expiry&lt;/strong&gt; — Each process individually decides whether to refresh before expiry, with probability increasing as expiry approaches. Simple to implement with no coordination overhead.&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;shouldEarlyRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ttlRemaining&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fullTtl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;beta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Higher beta = more aggressive early refresh&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ttlRemaining&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;fullTtl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;beta&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&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;&lt;strong&gt;Distributed lock&lt;/strong&gt; — Only one process is permitted to repopulate the key at a time. All others wait or return a stale value.&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="nx"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`lock:user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;NX&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="na"&gt;EX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// only set if not exists, expire in 10s&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;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We won the lock — repopulate&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`lock:user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Lost the lock — wait briefly and retry, or return a slightly stale value&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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;&lt;strong&gt;Background refresh with stale-while-revalidate&lt;/strong&gt; — Serve the stale value immediately while a single background process refreshes asynchronously. This is the refresh-ahead pattern applied reactively.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monitoring Cache Health
&lt;/h2&gt;

&lt;p&gt;A cache you cannot observe is a cache you cannot trust. Track these four metrics in production:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;th&gt;Action Threshold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hit rate&lt;/td&gt;
&lt;td&gt;Fraction of reads served from cache&lt;/td&gt;
&lt;td&gt;Investigate below 80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Miss rate&lt;/td&gt;
&lt;td&gt;Fraction of reads falling through to DB&lt;/td&gt;
&lt;td&gt;Spikes indicate TTL or eviction issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eviction rate&lt;/td&gt;
&lt;td&gt;Keys dropped due to memory pressure&lt;/td&gt;
&lt;td&gt;Any eviction = consider memory increase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency (p99)&lt;/td&gt;
&lt;td&gt;99th percentile cache round-trip&lt;/td&gt;
&lt;td&gt;Above 1 ms warrants investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instrument your cache-aside reads&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&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;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache.hit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;histogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache.latency_ms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache.miss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&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;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Caching is one of the highest-leverage tools in backend engineering. The five core patterns map cleanly to distinct use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache-Aside&lt;/strong&gt; — the safe, flexible default for read-heavy workloads&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read-Through&lt;/strong&gt; — same as cache-aside but encapsulated inside the cache layer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write-Through&lt;/strong&gt; — strong consistency on writes, acceptable write latency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write-Behind&lt;/strong&gt; — maximum write throughput, requires durable queuing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refresh-Ahead&lt;/strong&gt; — eliminates miss latency for predictable hot keys&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Master cache invalidation — TTL, event-driven delete, and versioned keys — before worrying about exotic patterns. Most real-world caching problems come down to stale data or stampedes, and both have well-understood solutions.&lt;/p&gt;

&lt;p&gt;Start with Redis, instrument hit rate from day one, and set &lt;code&gt;allkeys-lru&lt;/code&gt; as your eviction policy. Everything else you can tune iteratively as traffic grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is a good cache hit rate?&lt;/strong&gt; In most production workloads, a hit rate above 80% is the practical target. At 80% hit rate, roughly 80% of your database reads are eliminated. Below 70%, TTL tuning and key design should be revisited. Note that hit rate increases logarithmically with cache capacity — so the eviction policy and key design matter more than raw memory at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use Redis or a CDN for caching?&lt;/strong&gt; CDNs (Cloudflare, Fastly) cache at the network edge — ideal for static assets and API responses that are identical across users. Redis caches at the application layer — ideal for user-specific or frequently updated data. They are complementary, not alternatives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I invalidate cache entries across multiple services in a microservices architecture?&lt;/strong&gt; Use an event bus (Kafka, RabbitMQ, or Redis Pub/Sub). The service that owns the data publishes an invalidation event when it writes; all services that cache that data subscribe and delete their local entries. This is the event-driven invalidation pattern applied at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can caching make my application slower?&lt;/strong&gt; Yes, in two scenarios: cache miss rate is so high that you are adding a network round-trip to every database call (net negative), or cache lookup latency exceeds the database query you were trying to skip (rare, but happens with misconfigured Redis in high-latency networks). Monitor before deploying caching and measure after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a cold start / cold cache problem?&lt;/strong&gt; When your cache is empty — after a deployment, a restart, or provisioning a new node — all requests miss until entries are populated. For critical keys, pre-warm the cache at startup by reading from the database and populating keys before traffic is admitted.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/caching-strategies-every-backend-developer-must-know-k6qkb" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>caching</category>
      <category>redis</category>
      <category>backend</category>
    </item>
    <item>
      <title>Inside Claude's Brain: What Anthropic's Published System Prompts Reveal About the Future of AI Transparency</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Wed, 19 Aug 2026 05:34:23 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/inside-claudes-brain-what-anthropics-published-system-prompts-reveal-about-the-future-of-ai-2db0</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/inside-claudes-brain-what-anthropics-published-system-prompts-reveal-about-the-future-of-ai-2db0</guid>
      <description>&lt;h2&gt;
  
  
  The Page That Changed Everything
&lt;/h2&gt;

&lt;p&gt;In August 2024, a quiet page appeared on Anthropic's documentation site. No press release. No keynote. Just a URL — &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts" rel="noopener noreferrer"&gt;platform.claude.com/docs/en/release-notes/system-prompts&lt;/a&gt; — and a simple promise: from now on, Anthropic would publish the system prompts that govern how Claude behaves on claude.ai and its mobile apps.&lt;/p&gt;

&lt;p&gt;The initial entries were dated &lt;strong&gt;July 12, 2024&lt;/strong&gt;, covering Claude 3 Haiku, Claude 3 Opus, and Claude 3.5 Sonnet.&lt;/p&gt;

&lt;p&gt;Two years later, that page has become one of the most discussed artifacts in the AI industry. It regularly trends on Hacker News with hundreds of upvotes. Researchers diff it like source code. Developers treat it as a masterclass in prompt engineering. And it stands as a singular act of voluntary transparency in an industry that treats system prompts like nuclear launch codes.&lt;/p&gt;

&lt;p&gt;This is the story of what's inside those prompts — and what they tell us about where AI is heading.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a System Prompt, and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's establish what we're actually talking about.&lt;/p&gt;

&lt;p&gt;Every time you open Claude (or ChatGPT, or Gemini), the AI doesn't start with a blank slate. Before you type a single word, a hidden set of instructions — the &lt;strong&gt;system prompt&lt;/strong&gt; — has already been loaded.&lt;/p&gt;

&lt;p&gt;Think of it as an operating manual handed to a new employee on their first day: it defines who they are, how they should behave, what they're allowed to do, and what's strictly off-limits.&lt;/p&gt;

&lt;p&gt;These prompts shape &lt;em&gt;everything&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identity&lt;/strong&gt;: "You are Claude, created by Anthropic."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Temporal grounding&lt;/strong&gt;: The current date, so the model knows it's August 2026, not stuck in its training data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Knowledge boundaries&lt;/strong&gt;: What the model knows, and when to admit it doesn't.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Safety rails&lt;/strong&gt;: Hard lines around harmful content, illegal activities, and sensitive topics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personality&lt;/strong&gt;: Whether the AI sounds like a warm friend or a crisp professional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tool usage&lt;/strong&gt;: When and how to use search, code execution, file editing, and other capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system prompt is, in every meaningful sense, the AI's &lt;em&gt;constitution&lt;/em&gt;. And until Anthropic broke ranks, no major AI company had ever published theirs voluntarily.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Transparency Divide: Published vs. Leaked
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Let's look at how the three major AI labs handle this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Anthropic (Claude)&lt;/th&gt;
&lt;th&gt;OpenAI (ChatGPT)&lt;/th&gt;
&lt;th&gt;Google (Gemini)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;Voluntary publication&lt;/td&gt;
&lt;td&gt;Secrecy&lt;/td&gt;
&lt;td&gt;Secrecy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How prompts surface&lt;/td&gt;
&lt;td&gt;Official documentation&lt;/td&gt;
&lt;td&gt;Community leaks &amp;amp; prompt injection&lt;/td&gt;
&lt;td&gt;Community leaks &amp;amp; prompt injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update tracking&lt;/td&gt;
&lt;td&gt;Versioned release notes&lt;/td&gt;
&lt;td&gt;Reverse-engineered by researchers&lt;/td&gt;
&lt;td&gt;Reverse-engineered by researchers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer guidance&lt;/td&gt;
&lt;td&gt;High — prompt is the documentation&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;High for developer tools, low for consumer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAI and Google treat their system prompts as proprietary trade secrets. The only way the public sees them is through adversarial prompt injection — tricking the AI into repeating its hidden instructions.&lt;/p&gt;

&lt;p&gt;Alternatively, they surface through massive community-maintained GitHub repositories that have accumulated tens of thousands of stars.&lt;/p&gt;

&lt;p&gt;Anthropic simply... publishes them. On a public webpage. With a changelog.&lt;/p&gt;

&lt;p&gt;As Simon Willison, the prolific developer and AI commentator, put it: these published prompts are &lt;em&gt;"the secret missing manual"&lt;/em&gt; for the model. They reveal not just what Claude does, but &lt;em&gt;why&lt;/em&gt; it does it — which is information that developers working with ChatGPT or Gemini can only guess at.&lt;/p&gt;




&lt;h2&gt;
  
  
  Anatomy of a System Prompt: What's Actually in There
&lt;/h2&gt;

&lt;p&gt;So what does Claude's operating manual actually say?&lt;/p&gt;

&lt;p&gt;Based on Anthropic's published prompts (and community analysis of the more recent versions), the system prompt has grown from a relatively concise document into a comprehensive technical specification — often exceeding &lt;strong&gt;100,000 characters&lt;/strong&gt; in recent versions. It's organized into dozens of sections, typically 70 or more.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of the major categories:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Identity &amp;amp; Grounding
&lt;/h3&gt;

&lt;p&gt;The prompt opens by establishing who Claude is and when "now" is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;assistant&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Claude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;made&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dynamically&lt;/span&gt; &lt;span class="n"&gt;injected&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't just a formality. The date injection is critical for &lt;strong&gt;temporal grounding&lt;/strong&gt; — it lets Claude distinguish between events in its training data and events that happened after its knowledge cutoff.&lt;/p&gt;

&lt;p&gt;Without it, the model would confidently discuss the 2024 election as a future event.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Knowledge Boundaries
&lt;/h3&gt;

&lt;p&gt;The prompt explicitly instructs Claude on how to handle the gap between what it knows and what's happened since:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use internal knowledge for events within the training window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use search tools for anything recent or uncertain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Never fabricate information to fill gaps — acknowledge limitations instead.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the "honest" in Anthropic's &lt;em&gt;helpful, harmless, and honest&lt;/em&gt; framework. Rather than hallucinating a plausible-sounding answer, Claude is instructed to say "I'm not sure" — and, where possible, search for the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Safety &amp;amp; Ethics (The Hard Boundaries)
&lt;/h3&gt;

&lt;p&gt;This is the longest and most nuanced section. It covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Absolute refusals&lt;/strong&gt;: Weapons instructions, malware generation, CSAM, and other categories with zero exceptions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contextual judgment&lt;/strong&gt;: For ambiguous requests, Claude is instructed to &lt;em&gt;assume positive, legal intent&lt;/em&gt; rather than reflexively refusing. This is a deliberate design choice to avoid the "sorry, I can't help with that" problem that plagued earlier AI models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Child safety protocols&lt;/strong&gt;: If a conversation is flagged, the model applies "extreme caution" to all subsequent requests in that thread.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mental health&lt;/strong&gt;: Specific protocols for users expressing suicidal ideation or self-harm, including when to provide crisis resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Evenhandedness&lt;/strong&gt;: On politically controversial topics, Claude is instructed to present multiple perspectives without taking sides.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Formatting &amp;amp; Communication Style
&lt;/h3&gt;

&lt;p&gt;This is where the prompt gets surprisingly opinionated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No filler phrases&lt;/strong&gt;: Claude is explicitly told to avoid starting responses with "Certainly!", "Of course!", "Absolutely!" or similar sycophantic openers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Markdown by default&lt;/strong&gt;: Code should be formatted with syntax highlighting; complex answers should use headers and lists.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conciseness&lt;/strong&gt;: Lead with the direct answer, then elaborate. Don't bury the lede.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Match the user's register&lt;/strong&gt;: If someone writes casually, respond casually. If they write formally, match their tone.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Tool Definitions &amp;amp; Capabilities
&lt;/h3&gt;

&lt;p&gt;In the consumer-facing claude.ai product, the system prompt contains detailed schemas for every tool Claude can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web search&lt;/strong&gt;: When to search, how to cite sources, how to handle copyright.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code execution&lt;/strong&gt;: Sandboxed environments for running Python, generating visualizations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File handling&lt;/strong&gt;: Reading uploaded documents, processing images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specialized agents&lt;/strong&gt;: Browsing assistants, spreadsheet processors, presentation builders.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Community researchers note that tool definitions often consume the &lt;em&gt;majority&lt;/em&gt; of the system prompt's token budget — sometimes more than all the personality, safety, and formatting instructions combined.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. The "Meta" Instructions
&lt;/h3&gt;

&lt;p&gt;Perhaps the most fascinating section: instructions about the instructions themselves.&lt;/p&gt;

&lt;p&gt;Claude is told how to handle attempts to extract or manipulate its system prompt. It's instructed to be transparent about having a system prompt (it won't deny it exists), but not to reproduce it verbatim.&lt;/p&gt;

&lt;p&gt;It's also told to prioritize its core safety instructions even if a user's prompt contradicts them — establishing a clear hierarchy of authority.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Evolution: How the Prompts Have Changed Over Time
&lt;/h2&gt;

&lt;p&gt;One of the most valuable aspects of Anthropic's transparency is that it creates a &lt;strong&gt;public changelog&lt;/strong&gt; for AI behavior. Researchers like Simon Willison have exploited this brilliantly, using tools like &lt;code&gt;git diff&lt;/code&gt; to track exactly how Claude's personality and capabilities shift between versions.&lt;/p&gt;

&lt;p&gt;Here are some of the most notable evolutionary trends:&lt;/p&gt;

&lt;h3&gt;
  
  
  From Warm to Direct (2024 → 2025)
&lt;/h3&gt;

&lt;p&gt;Early Claude prompts emphasized warmth and empathy. The model was positioned as a &lt;em&gt;friendly brainstorming partner&lt;/em&gt;. By mid-2025, the tone had shifted: Claude became more of a &lt;em&gt;direct, opinionated expert&lt;/em&gt; — someone who gives you the answer rather than asking how you feel about it.&lt;/p&gt;

&lt;p&gt;This wasn't accidental. User feedback consistently showed that people preferred Claude when it was confident and direct, not when it hedged everything with qualifiers.&lt;/p&gt;

&lt;h3&gt;
  
  
  From Verbose to Lean (2025 → 2026)
&lt;/h3&gt;

&lt;p&gt;A surprising trend: Anthropic has been &lt;em&gt;reducing&lt;/em&gt; the length of its safety instructions in recent prompts. Not because they care less about safety, but because frontier models have internalized these behaviors through training.&lt;/p&gt;

&lt;p&gt;As Anthropic's own research has noted, the shift is from "prompt engineering" to &lt;strong&gt;"context engineering"&lt;/strong&gt; — recognizing that a model with deep constitutional training needs fewer explicit rules in its prompt and more contextual framing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tool Explosion (2024 → 2026)
&lt;/h3&gt;

&lt;p&gt;The most dramatic growth has been in tool definitions. The original prompts had minimal tool integration. By 2026, tool schemas for search, code execution, computer use, and specialized agents dominate the prompt. Claude has evolved from a text-in/text-out chatbot into an &lt;strong&gt;agentic system&lt;/strong&gt; that can browse the web, write and execute code, and interact with external services.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fable/Mythos Architecture (June 2026)
&lt;/h3&gt;

&lt;p&gt;The release of &lt;strong&gt;Claude Fable 5&lt;/strong&gt; and &lt;strong&gt;Claude Mythos 5&lt;/strong&gt; on June 9, 2026, introduced a new dimension to system prompt design: &lt;strong&gt;tiered safety classifiers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Fable 5 and Mythos 5 are the same underlying model — the most capable Anthropic has ever released — but with different safety postures. Fable 5 includes safety classifiers that monitor for sensitive domains (cybersecurity, biology, chemistry); if triggered, it falls back to Claude Opus 4.8 for that response.&lt;/p&gt;

&lt;p&gt;Mythos 5 lifts those classifiers and is restricted to vetted partners through Anthropic's &lt;strong&gt;Project Glasswing&lt;/strong&gt; initiative.&lt;/p&gt;

&lt;p&gt;This architecture means the system prompt alone no longer tells the full story — the prompt now works in concert with external classifier layers that can override the model's output entirely.&lt;/p&gt;

&lt;p&gt;Just days after launch, both models were &lt;strong&gt;temporarily suspended globally&lt;/strong&gt; (June 12–July 1, 2026) due to a U.S. government export control directive.&lt;/p&gt;

&lt;p&gt;The incident was a stress test for Anthropic's transparency commitment: they documented the suspension and restoration publicly, rather than quietly limiting access. For a company that publishes its system prompts, this consistency mattered.&lt;/p&gt;

&lt;p&gt;The subsequent release of &lt;strong&gt;Claude Opus 5&lt;/strong&gt; on July 24, 2026 — designed to approach Fable 5's intelligence at a lower price point — further expanded the system prompt landscape across an increasingly diverse model lineup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Child Safety Escalation
&lt;/h3&gt;

&lt;p&gt;Each prompt revision has strengthened child safety protocols. Recent versions implement a "ratcheting" mechanism: once a conversation triggers a safety flag, the model's caution level increases for &lt;em&gt;all subsequent messages in that thread&lt;/em&gt;, not just the flagged one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters: Five Lessons From the System Prompts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The AI's "Personality" Is Engineered, Not Emergent
&lt;/h3&gt;

&lt;p&gt;When Claude gives you a thoughtful, nuanced answer, it's not because it spontaneously developed good judgment. It's because someone at Anthropic wrote instructions telling it to "present multiple perspectives on controversial topics" and "lead with the direct answer."&lt;/p&gt;

&lt;p&gt;The system prompt reveals that what feels like intelligence is, in part, careful UX design. This isn't a criticism — it's a feature. But it means we should evaluate AI responses knowing that they're shaped by editorial decisions, not just raw capability.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Safety Is Not a Binary Switch
&lt;/h3&gt;

&lt;p&gt;The prompts reveal a sophisticated, context-dependent approach to safety. Claude doesn't have a simple "allowed/not allowed" list. It has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Absolute prohibitions&lt;/strong&gt; (weapons, CSAM) — no context overrides these.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contextual judgment&lt;/strong&gt; — assume positive intent for ambiguous requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escalation protocols&lt;/strong&gt; — increase caution within flagged conversations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Domain-specific rules&lt;/strong&gt; — different handling for medical questions vs. legal questions vs. creative writing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This multi-layered approach is far more nuanced than most people realize, and it's a template that other AI companies will likely adopt.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Prompt Is a Product Specification
&lt;/h3&gt;

&lt;p&gt;Reading Claude's system prompt is like reading the product requirements document for a software application. It defines features, edge cases, error handling, and user experience guidelines. This reframes how we should think about AI development: the system prompt isn't an afterthought bolted onto the model — it's a core part of the product design.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Transparency Creates Accountability
&lt;/h3&gt;

&lt;p&gt;Once you publish your AI's instructions, you can be held to them. If Claude's system prompt says "present balanced perspectives on political topics," users can call out violations. If it says "don't start responses with 'Certainly!'" and then it does, that's a measurable bug.&lt;/p&gt;

&lt;p&gt;This is a radical departure from the black-box model, where AI companies can change behavior without anyone noticing. Anthropic has, in effect, given users a contract they can audit.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The Industry Will Follow
&lt;/h3&gt;

&lt;p&gt;The EU AI Act and other global regulations are pushing toward mandatory transparency for high-risk AI systems. Open-source models like Llama and Mistral already publish their entire architectures. As public demand for AI accountability grows, the "publish your system prompt" approach will likely become the industry norm by 2027–2028.&lt;/p&gt;

&lt;p&gt;Anthropic got there first, and that matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Prompts Don't Tell You
&lt;/h2&gt;

&lt;p&gt;Transparency has limits, and it's worth acknowledging what Anthropic's published prompts leave out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tool definitions are omitted&lt;/strong&gt;: The published prompts strip out the detailed JSON schemas for tools like search and code execution. These are arguably the most technically interesting parts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API prompts are not included&lt;/strong&gt;: The published prompts apply only to claude.ai and the mobile apps. If you use the Anthropic API, you're responsible for your own system prompt — and the API does not inject these instructions automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude Code has different prompts&lt;/strong&gt;: The CLI-based coding tool has its own, separately maintained (and not officially published) system prompt that's dynamically assembled from hundreds of conditional strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Safety classifiers are separate&lt;/strong&gt;: With the Fable 5/Mythos 5 architecture, external safety classifiers can override model output independently of the system prompt. These classifier rules and thresholds are not published.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Training alignment isn't visible&lt;/strong&gt;: The system prompt is only one layer of Claude's behavior. The deeper layer — reinforcement learning from human feedback (RLHF) and constitutional AI training — is not captured in the prompt and isn't publicly visible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These omissions are worth noting, but they don't diminish the significance of what &lt;em&gt;is&lt;/em&gt; published. The system prompt is the most legible, most auditable layer of AI behavior, and making it public is a meaningful act of trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  For Developers: What You Can Learn From These Prompts
&lt;/h2&gt;

&lt;p&gt;If you're building with the Claude API (or any LLM), Anthropic's published prompts are a goldmine of prompt engineering patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure with XML Tags
&lt;/h3&gt;

&lt;p&gt;Anthropic uses XML-style tags to organize different sections of the prompt (&lt;code&gt;&amp;lt;safety_guidelines&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;formatting_rules&amp;gt;&lt;/code&gt;, etc.). This helps the model parse complex instructions without confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be Specific About What NOT to Do
&lt;/h3&gt;

&lt;p&gt;The prompts don't just say "be helpful." They explicitly list anti-patterns: don't start with filler phrases, don't hedge when you're confident, don't refuse ambiguous requests without considering positive intent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set a Clear Instruction Hierarchy
&lt;/h3&gt;

&lt;p&gt;The prompts establish explicit priority: core safety &amp;gt; system prompt &amp;gt; user instructions. This prevents prompt injection attacks from overriding safety-critical behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inject Dynamic Context
&lt;/h3&gt;

&lt;p&gt;Rather than relying on the model's training data for temporal awareness, the prompt injects the current date at runtime. This pattern — dynamic context injection — is essential for any production AI application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design for Edge Cases
&lt;/h3&gt;

&lt;p&gt;The prompts devote significant space to edge cases: what happens when a user is suicidal, when a conversation gets flagged, when a request is ambiguous. Production AI systems fail on edge cases, and Anthropic's prompts show how to handle them systematically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture: AI's Open-Source Constitution
&lt;/h2&gt;

&lt;p&gt;There's something poetically fitting about an AI company publishing the rules that govern its AI. It's the software equivalent of a government publishing its constitution — an acknowledgment that the rules should be visible to the governed.&lt;/p&gt;

&lt;p&gt;Anthropic calls its approach &lt;strong&gt;Constitutional AI&lt;/strong&gt;, and the system prompt is where that constitution becomes operational.&lt;/p&gt;

&lt;p&gt;It's where abstract values like "helpful, harmless, and honest" get translated into concrete instructions: &lt;em&gt;this is what honest looks like when someone asks about a controversial politician; this is what harmless looks like when someone mentions self-harm; this is what helpful looks like when someone needs code reviewed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As AI systems become more powerful and more autonomous — writing code, browsing the web, managing workflows — the question of "what rules is this thing following?" becomes not just academic but urgent.&lt;/p&gt;

&lt;p&gt;Anthropic's system prompts page is one answer to that question. It's imperfect, it's incomplete, but it exists.&lt;/p&gt;

&lt;p&gt;And in an industry where the default is to hide everything, existence is a radical act.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What&lt;/strong&gt;: Anthropic publishes the system prompts for Claude on &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts" rel="noopener noreferrer"&gt;platform.claude.com/docs/en/release-notes/system-prompts&lt;/a&gt; — the only major AI lab to do so voluntarily.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why it matters&lt;/strong&gt;: These prompts are Claude's operating manual — they define identity, safety rules, formatting preferences, tool usage, and personality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What's inside&lt;/strong&gt;: 70+ sections covering everything from "don't say Certainly!" to child safety escalation protocols and multi-layered tool definitions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How they've evolved&lt;/strong&gt;: From warm-and-fuzzy to direct-and-expert, from minimal tools to a full agentic toolkit, from verbose safety rules to lean, training-aligned instructions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The industry impact&lt;/strong&gt;: OpenAI and Google keep their prompts secret; Anthropic's transparency sets a standard that regulation and competition will eventually force others to meet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For developers&lt;/strong&gt;: The prompts are a masterclass in prompt engineering — study them for patterns in structure, safety, dynamic context injection, and edge case handling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;The system prompts page is available at&lt;/em&gt; &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts" rel="noopener noreferrer"&gt;&lt;em&gt;platform.claude.com/docs/en/release-notes/system-prompts&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. For ongoing analysis, follow Simon Willison's blog at&lt;/em&gt; &lt;a href="https://simonwillison.net" rel="noopener noreferrer"&gt;&lt;em&gt;simonwillison.net&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, where he tracks prompt changes with git-style diffs.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/inside-claude-s-brain-what-anthropic-s-published-system-prompts-reveal-about-the-future-of-ai-transparency-yjkk5" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Hide Your Backend VPS IP Behind Vercel Using Next.js Rewrites</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Tue, 18 Aug 2026 06:32:01 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/how-to-hide-your-backend-vps-ip-behind-vercel-using-nextjs-rewrites-1a5</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/how-to-hide-your-backend-vps-ip-behind-vercel-using-nextjs-rewrites-1a5</guid>
      <description>&lt;p&gt;If you host your frontend on Vercel and your backend on a custom VPS, your frontend usually makes API requests directly to the VPS's public IP address or domain. While this works, it exposes your backend server's true IP address to the world, making it vulnerable to direct DDoS attacks, port scanners, and malicious bots.&lt;/p&gt;

&lt;p&gt;By using &lt;strong&gt;Vercel Rewrites&lt;/strong&gt;, you can use Vercel's edge network as a shield. To the outside world, your API requests appear to be going to Vercel, while Vercel secretly fetches the data from your VPS behind the scenes.&lt;/p&gt;

&lt;p&gt;Here is how you can set up a secure API proxy in Next.js (App Router) and lock down your backend to reject any request that tries to bypass Vercel.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
    actor User
    participant Vercel as Vercel (Next.js)
    participant VPS as VPS (NestJS Backend)

    User-&amp;gt;&amp;gt;Vercel: Fetch /api-proxy/data
    Note over Vercel: Middleware injects secret header&amp;lt;br/&amp;gt;next.config.ts rewrites path
    Vercel-&amp;gt;&amp;gt;VPS: Fetch /data (with Secret Header)

    alt Valid Secret
        VPS--&amp;gt;&amp;gt;Vercel: 200 OK (Data)
        Vercel--&amp;gt;&amp;gt;User: 200 OK (Data)
    else Missing/Invalid Secret
        VPS--&amp;gt;&amp;gt;Vercel: 403 Forbidden
    end

    User-xVPS: Direct Request (Blocked 403)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Configure Next.js Rewrites
&lt;/h2&gt;

&lt;p&gt;First, we need to tell Next.js to intercept requests made to a specific proxy path (e.g., &lt;code&gt;/api-proxy/*&lt;/code&gt;) and forward them to your VPS. We achieve this by adding a rewrite rule to &lt;code&gt;next.config.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To ensure we don't accidentally create proxy loops, we will use a specific environment variable &lt;code&gt;BACKEND_URL&lt;/code&gt; solely for the rewrite destination.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// next.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;rewrites&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The true IP of your VPS, safely hidden in Vercel environment variables&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BACKEND_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4000&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api-proxy/:path*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/:path*`&lt;/span&gt; 
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&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;h2&gt;
  
  
  Step 2: Inject a Secret Header at the Edge
&lt;/h2&gt;

&lt;p&gt;Now that the request is proxying through Vercel, we need a way for our backend to know that the request &lt;em&gt;actually&lt;/em&gt; came from Vercel. We do this by injecting a secret header.&lt;/p&gt;

&lt;p&gt;In Next.js, we can use Edge Middleware to intercept the request and inject the header before the &lt;code&gt;next.config.ts&lt;/code&gt; rewrite takes effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// middleware.ts (or proxy.ts if you use a custom setup)&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;NextResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&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="nx"&gt;requestHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxySecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_PROXY_SECRET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Inject the secret key into the headers&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;proxySecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;requestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-vercel-proxy-secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;proxySecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Pass the modified headers along to the Next.js rewrite engine&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;requestHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="p"&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;/api-proxy/:path*&lt;/span&gt;&lt;span class="dl"&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;h2&gt;
  
  
  Step 3: Lock Down the Backend
&lt;/h2&gt;

&lt;p&gt;If an attacker guesses your VPS IP, they could still bypass Vercel entirely. We need to configure the backend to reject any request that lacks the secret header.&lt;/p&gt;

&lt;p&gt;Here is an example of how to enforce this using a global hook in a &lt;strong&gt;NestJS + Fastify&lt;/strong&gt; backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// backend/src/main.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fastifyInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpAdapter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;fastifyInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onRequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxySecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_PROXY_SECRET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Exclude localhost (127.0.0.1) so internal Docker health checks still work!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLocal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;::1&lt;/span&gt;&lt;span class="dl"&gt;'&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;proxySecret&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isLocal&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="nx"&gt;incomingSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-vercel-proxy-secret&lt;/span&gt;&lt;span class="dl"&gt;'&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;incomingSecret&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;proxySecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Forbidden: Invalid proxy secret&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;done&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;blockquote&gt;
&lt;p&gt;[!TIP] &lt;strong&gt;Docker Health Checks:&lt;/strong&gt; Notice the &lt;code&gt;isLocal&lt;/code&gt; check. If you use Docker, your container's internal health check pinging &lt;code&gt;localhost&lt;/code&gt; won't have the secret header. Bypassing the check for local IPs prevents your deployments from rolling back due to failed health checks!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: Fixing Server-Side Rendering (SSR/SSG)
&lt;/h2&gt;

&lt;p&gt;There's one hidden "gotcha" with this setup. During the Next.js build process (&lt;code&gt;next build&lt;/code&gt;), Next.js generates static pages and makes fetch requests directly to your backend API.&lt;/p&gt;

&lt;p&gt;Because these requests originate from the build server and bypass your Next.js middleware, they &lt;strong&gt;will fail with a 403 Forbidden error&lt;/strong&gt; because they lack the &lt;code&gt;x-vercel-proxy-secret&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;To fix this, you must manually inject the secret into your internal API client or Apollo Client configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/apollo-server.ts&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;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InMemoryCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpLink&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;@apollo/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;const&lt;/span&gt; &lt;span class="nx"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_API_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apolloServerClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;ssrMode&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="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpLink&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/graphql`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_PROXY_SECRET&lt;/span&gt; 
      &lt;span class="p"&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;x-vercel-proxy-secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_PROXY_SECRET&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryCache&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;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By combining Next.js rewrites, Edge middleware, and a simple backend validation check, you can successfully shield your custom VPS behind Vercel's robust infrastructure. Your true IP address remains a secret, and your API is locked down against direct unauthorized access!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/how-to-hide-your-backend-vps-ip-behind-vercel-using-next-js-rewrites-iwb51" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>nestjs</category>
      <category>backend</category>
      <category>security</category>
    </item>
    <item>
      <title>Google Launches Gemini 3.7 Flash Three Weeks After 3.6 With 50% Introductory Pricing</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Mon, 17 Aug 2026 10:53:24 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/google-launches-gemini-37-flash-three-weeks-after-36-with-50-introductory-pricing-20b3</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/google-launches-gemini-37-flash-three-weeks-after-36-with-50-introductory-pricing-20b3</guid>
      <description>&lt;p&gt;Google DeepMind released &lt;strong&gt;Gemini 3.7 Flash on August 13, 2026&lt;/strong&gt;, just three weeks after Gemini 3.6 Flash. This is not a new model family or a full generational reset. Google describes it as the next iteration in the Gemini 3 line, based on Gemini 3.6 Flash with algorithmic improvements to its reasoning foundation.&lt;/p&gt;

&lt;p&gt;That distinction matters. The interesting question is not whether Gemini 3.7 Flash is simply “smarter.” It is whether Google has made a fast, relatively inexpensive model good enough to handle more real production work—especially coding, tool use, web development, and business workflows—without requiring the cost of a larger frontier model.&lt;/p&gt;

&lt;p&gt;Google is clearly positioning it that way. Its announcement calls 3.7 Flash its “most intelligent workhorse model yet” for coding and agents, while the model card emphasizes agentic workflows, coding tasks, and enterprise workflows as intended uses. &lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/introducing-gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google&lt;/a&gt; &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed in Gemini 3.7 Flash?
&lt;/h2&gt;

&lt;p&gt;Gemini 3.7 Flash is built on Gemini 3.6 Flash rather than being trained as a completely separate architecture. Google says the model introduces algorithmic improvements to its core reasoning foundation and supports customizable thinking configurations that let developers trade off quality, cost, and latency.&lt;/p&gt;

&lt;p&gt;The basic model envelope remains substantial: up to a &lt;strong&gt;1-million-token context window&lt;/strong&gt;, &lt;strong&gt;64K-token output&lt;/strong&gt;, and multimodal input across &lt;strong&gt;text, images, audio, and video&lt;/strong&gt;. The knowledge cutoff is &lt;strong&gt;March 2026&lt;/strong&gt;. &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Gemini 3.7 Flash&lt;/th&gt;
&lt;th&gt;Gemini 3.6 Flash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Context window&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;td&gt;1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum output&lt;/td&gt;
&lt;td&gt;64K tokens&lt;/td&gt;
&lt;td&gt;64K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input modalities&lt;/td&gt;
&lt;td&gt;Text, image, audio, video&lt;/td&gt;
&lt;td&gt;Text, image, audio, video&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thinking&lt;/td&gt;
&lt;td&gt;Configurable&lt;/td&gt;
&lt;td&gt;Configurable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge cutoff&lt;/td&gt;
&lt;td&gt;March 2026&lt;/td&gt;
&lt;td&gt;January 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model dependency&lt;/td&gt;
&lt;td&gt;Based on 3.6 Flash&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API model name&lt;/td&gt;
&lt;td&gt;gemini-3.7-flash&lt;/td&gt;
&lt;td&gt;gemini-3.6-flash&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important change is not a larger context window or a radically different interface. It is getting &lt;strong&gt;more useful work out of the Flash model class&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the Thinking Level
&lt;/h3&gt;

&lt;p&gt;Configurable thinking gives developers control over the quality/cost/latency trade-off, which matters when one request can trigger multiple model calls and tool interactions. Think of it as an engineering choice rather than a simple “higher is better” switch:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A([Incoming Request]) --&amp;gt; B{Primary priority?}
    B --&amp;gt;|Lower latency / cost| C[Use lighter thinking\nFast responses\nSimple classification\nRoutine tasks]
    B --&amp;gt;|Balanced| D[Use moderate thinking\nCoding\nAgent workflows\nGeneral tasks]
    B --&amp;gt;|Hard reasoning| E[Use deeper thinking\nComplex debugging\nMulti-step planning\nDifficult analysis]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The exact settings available depend on the API and model configuration, so developers should treat thinking as a tunable resource rather than a universal preset.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Biggest Gains Are in Software Engineering
&lt;/h2&gt;

&lt;p&gt;Coding is where Gemini 3.7 Flash makes its clearest case.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;FrontierCode 1.1 Main&lt;/strong&gt;, Google's published result is &lt;strong&gt;43.6%&lt;/strong&gt;, up from &lt;strong&gt;34.4%&lt;/strong&gt; for Gemini 3.6 Flash. On &lt;strong&gt;DeepSWE v1.1&lt;/strong&gt;, which measures long-horizon software engineering, 3.7 Flash reaches &lt;strong&gt;65.3%&lt;/strong&gt;, compared with &lt;strong&gt;48.6%&lt;/strong&gt; for 3.6 Flash.&lt;/p&gt;

&lt;p&gt;The competitive picture is more nuanced. Gemini 3.7 Flash is ahead of Claude Sonnet 5 on FrontierCode, but &lt;strong&gt;GPT-5.6 Terra remains ahead on DeepSWE at 69.6%&lt;/strong&gt;. That matters because long-horizon software engineering is closer to the kind of multi-file, multi-step work developers increasingly expect from coding agents. &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terminal evaluations tell a similar story. Gemini 3.7 Flash scores &lt;strong&gt;85.8% on Terminal-bench 2.1&lt;/strong&gt;, up from 78.0% for 3.6 Flash. On the harder &lt;strong&gt;Terminal-bench 3.0&lt;/strong&gt;, it reaches 14.9%, versus 5.4% for 3.6 Flash. GPT-5.6 Terra still leads Terminal-bench 3.0 at 20.8%.&lt;/p&gt;

&lt;p&gt;The takeaway is more useful than any single score: the model is getting better at &lt;strong&gt;doing engineering work through tools&lt;/strong&gt;, not just answering isolated coding questions.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;xychart-beta
    title "Gemini 3.7 Flash: Improvement Over 3.6 Flash"
    x-axis ["FrontierCode", "DeepSWE", "AutomationBench", "GDP.pdf", "LABBench2", "HLE"]
    y-axis "Improvement (percentage points)" 0 --&amp;gt; 20
    bar [9.2, 16.7, 13.4, 12.0, 6.0, 2.4]&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Web Development and UI Generation
&lt;/h2&gt;

&lt;p&gt;Web development is another notable focus.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;Code Arena's WebDev Arena&lt;/strong&gt;, Gemini 3.7 Flash scores &lt;strong&gt;1,588 Elo&lt;/strong&gt;, compared with &lt;strong&gt;1,538&lt;/strong&gt; for Gemini 3.6 Flash. It also ranks above Claude Sonnet 5 at 1,541 and GPT-5.6 Terra at 1,523 in Google's published comparison.&lt;/p&gt;

&lt;p&gt;Google says the model can produce more functional layouts and feature-complete applications in fewer prompts. It also highlights stronger adherence to reference designs, screenshots, and design systems.&lt;/p&gt;

&lt;p&gt;That matters for frontend developers because the useful benchmark is not “can the model write React?” Modern coding assistants already can. The harder problem is whether the model can translate a visual or product specification into a working interface without requiring a long sequence of corrective prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documents, Legal Work, and Business Automation
&lt;/h2&gt;

&lt;p&gt;Gemini 3.7 Flash also makes a strong showing outside traditional coding benchmarks.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;GDP.pdf&lt;/strong&gt;, a document-comprehension benchmark, it scores &lt;strong&gt;34.0%&lt;/strong&gt;, up from 22.0% for Gemini 3.6 Flash. On &lt;strong&gt;Harvey LAB-AA&lt;/strong&gt;, which evaluates complex legal workflows, it reaches &lt;strong&gt;90.7%&lt;/strong&gt;, narrowly ahead of Claude Sonnet 5 at 90.1%.&lt;/p&gt;

&lt;p&gt;The most striking number may be &lt;strong&gt;AutomationBench&lt;/strong&gt;. Gemini 3.7 Flash reaches &lt;strong&gt;30.4%&lt;/strong&gt;, compared with 17.0% for 3.6 Flash. Google's model card notes that AutomationBench is a private set, so the result should be interpreted primarily as a directional comparison rather than a universally reproducible leaderboard number.&lt;/p&gt;

&lt;p&gt;That distinction is important. Private benchmarks can tell us that a model improved relative to another model under a particular evaluation setup, but they do not give developers the same reproducibility as a public benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasoning and Scientific Work
&lt;/h2&gt;

&lt;p&gt;The model's gains are not limited to business tasks.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;HLE-Verified&lt;/strong&gt;, Gemini 3.7 Flash scores &lt;strong&gt;53.6%&lt;/strong&gt;, up from 51.2% for 3.6 Flash and above Claude Sonnet 5 at 31.0%. On &lt;strong&gt;LABBench2&lt;/strong&gt;, which evaluates biology research tasks, it reaches &lt;strong&gt;82.1%&lt;/strong&gt;, compared with 76.1% for its predecessor.&lt;/p&gt;

&lt;p&gt;There are regressions too. On &lt;strong&gt;CharXiv without tools&lt;/strong&gt;, 3.7 Flash scores 84.5%, slightly below 3.6 Flash at 85.2%. With tools enabled, 3.6 Flash also remains ahead, 89.4% to 88.7%.&lt;/p&gt;

&lt;p&gt;That is a useful reminder that “model improvement” is not a monotonic property. A release can improve substantially on coding and agentic workflows while moving backward on a narrower class of reasoning tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gemini 3.7 Flash vs the Competition
&lt;/h2&gt;

&lt;p&gt;Here is the more useful snapshot from Google's published evaluation table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Gemini 3.7 Flash&lt;/th&gt;
&lt;th&gt;Gemini 3.6 Flash&lt;/th&gt;
&lt;th&gt;Claude Sonnet 5&lt;/th&gt;
&lt;th&gt;GPT-5.6 Terra&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FrontierCode 1.1 Main&lt;/td&gt;
&lt;td&gt;43.6%&lt;/td&gt;
&lt;td&gt;34.4%&lt;/td&gt;
&lt;td&gt;42.7%&lt;/td&gt;
&lt;td&gt;41.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSWE v1.1&lt;/td&gt;
&lt;td&gt;65.3%&lt;/td&gt;
&lt;td&gt;48.6%&lt;/td&gt;
&lt;td&gt;53.8%&lt;/td&gt;
&lt;td&gt;69.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebDev / Code Arena&lt;/td&gt;
&lt;td&gt;1,588 Elo&lt;/td&gt;
&lt;td&gt;1,538&lt;/td&gt;
&lt;td&gt;1,541&lt;/td&gt;
&lt;td&gt;1,523&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-bench 2.1&lt;/td&gt;
&lt;td&gt;85.8%&lt;/td&gt;
&lt;td&gt;78.0%&lt;/td&gt;
&lt;td&gt;80.4%&lt;/td&gt;
&lt;td&gt;87.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-bench 3.0&lt;/td&gt;
&lt;td&gt;14.9%&lt;/td&gt;
&lt;td&gt;5.4%&lt;/td&gt;
&lt;td&gt;14.6%&lt;/td&gt;
&lt;td&gt;20.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AutomationBench&lt;/td&gt;
&lt;td&gt;30.4%&lt;/td&gt;
&lt;td&gt;17.0%&lt;/td&gt;
&lt;td&gt;10.7%&lt;/td&gt;
&lt;td&gt;23.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GDP.pdf&lt;/td&gt;
&lt;td&gt;34.0%&lt;/td&gt;
&lt;td&gt;22.0%&lt;/td&gt;
&lt;td&gt;28.0%&lt;/td&gt;
&lt;td&gt;24.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Harvey LAB-AA&lt;/td&gt;
&lt;td&gt;90.7%&lt;/td&gt;
&lt;td&gt;85.1%&lt;/td&gt;
&lt;td&gt;90.1%&lt;/td&gt;
&lt;td&gt;85.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HLE-Verified&lt;/td&gt;
&lt;td&gt;53.6%&lt;/td&gt;
&lt;td&gt;51.2%&lt;/td&gt;
&lt;td&gt;31.0%&lt;/td&gt;
&lt;td&gt;51.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OSWorld-2.0&lt;/td&gt;
&lt;td&gt;47.9%&lt;/td&gt;
&lt;td&gt;33.8%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;50.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Intelligence Index&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Source: &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind Gemini 3.7 Flash model card&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The table makes the central point clear: &lt;strong&gt;Gemini 3.7 Flash is not the universal benchmark leader. It wins important categories while remaining below the frontier on several of the hardest agentic evaluations.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pricing Story May Matter More Than the Leaderboard
&lt;/h2&gt;

&lt;p&gt;For production systems, benchmark position is only half the equation. The other half is what it costs to run the model repeatedly.&lt;/p&gt;

&lt;p&gt;Google is launching Gemini 3.7 Flash at an introductory price of &lt;strong&gt;$0.75 per million input tokens and $3.75 per million output tokens&lt;/strong&gt; through December 31, 2026. Starting January 1, 2027, the price becomes &lt;strong&gt;$1.50 per million input tokens and $7.50 per million output tokens&lt;/strong&gt;. &lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/introducing-gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google&lt;/a&gt; &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is why the headline should be understood as &lt;strong&gt;50% introductory pricing relative to the original 3.6 Flash launch price&lt;/strong&gt;, not as a permanent price cut.&lt;/p&gt;

&lt;p&gt;For a simple 80/20 input-output workload, the blended cost is roughly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input / 1M&lt;/th&gt;
&lt;th&gt;Output / 1M&lt;/th&gt;
&lt;th&gt;Approx. 80/20 blended cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.7 Flash — intro&lt;/td&gt;
&lt;td&gt;$0.75&lt;/td&gt;
&lt;td&gt;$3.75&lt;/td&gt;
&lt;td&gt;$1.35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.7 Flash — from Jan. 2027&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;td&gt;$7.50&lt;/td&gt;
&lt;td&gt;$2.70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;~$3.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Terra&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;td&gt;$12.00&lt;/td&gt;
&lt;td&gt;~$4.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The real economic question is &lt;strong&gt;cost per successful task&lt;/strong&gt;. A cheaper model that needs more retries, tool calls, or human correction may not actually be cheaper. That is where 3.7 Flash’s coding and tool-use gains become commercially interesting.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;timeline
    title Gemini 3.7 Flash Pricing Lifecycle
    Aug 13 2026 : Introductory launch
               : $0.75 input / 1M
               : $3.75 output / 1M
    Dec 31 2026 : Introductory pricing expires
    Jan 1 2027  : Standard rate begins
               : $1.50 input / 1M
               : $7.50 output / 1M&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Where Gemini 3.7 Flash Still Trails
&lt;/h2&gt;

&lt;p&gt;The strongest case for Gemini 3.7 Flash is not that it dominates every benchmark. It doesn't.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Artificial Analysis Intelligence Index&lt;/strong&gt; puts Gemini 3.7 Flash at 56, behind GPT-5.6 Terra at 57. On DeepSWE, GPT-5.6 Terra retains a meaningful 4.3-point lead. GPT-5.6 Terra also leads Terminal-bench 2.1, Terminal-bench 3.0, and OSWorld-2.0 in Google's comparison.&lt;/p&gt;

&lt;p&gt;Those gaps matter for teams building agents that must operate across long, unpredictable sequences of actions. A 14.9% score on Terminal-bench 3.0 is dramatically better than 5.4% for the previous model, but it is still far from a solved problem.&lt;/p&gt;

&lt;p&gt;That is the more realistic way to view this release: &lt;strong&gt;Gemini 3.7 Flash moves the cheaper Flash tier closer to frontier capability, but it does not erase the gap between a fast workhorse model and the best-performing models on the hardest agentic tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Release Means for Developers
&lt;/h2&gt;

&lt;p&gt;For developers, the appeal is straightforward: &lt;strong&gt;better coding without moving to a more expensive tier, cheaper agentic workflows, and broader production use across coding, documents, web development, and automation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That suggests a shift in how models should be evaluated. The better question is not “Which model has the highest benchmark score?” but “Which model can complete my workflow reliably at a cost I can scale?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;p&gt;Gemini 3.7 Flash is available through the &lt;strong&gt;Gemini API, Google AI Studio, Android Studio, Google Antigravity, Gemini Enterprise Agent Platform, and the Gemini Enterprise app&lt;/strong&gt;. Google also says Gemini Spark will use 3.7 Flash for Google AI Pro and Ultra subscribers in supported countries. &lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/introducing-gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google&lt;/a&gt; &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model card lists the API, AI Studio, Antigravity, and enterprise channels explicitly. Developers should still check the current API documentation before migrating production workloads because model availability, parameters, and pricing can change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety and Limitations
&lt;/h2&gt;

&lt;p&gt;Google says Gemini 3.7 Flash ships with updated safeguards targeting misuse in &lt;strong&gt;CBRN and cyber offense&lt;/strong&gt; domains. Its Frontier Safety assessment reports that the model did not reach tracked or critical capability thresholds, although it did reach the alert threshold for the Level 1 cybersecurity critical-capability category without crossing the capability threshold itself. &lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind model card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model card also lists familiar foundation-model limitations, including hallucinations and possible slowness or timeouts. For high-stakes applications, developers still need application-level validation, permission boundaries, monitoring, and fallback paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Release Signals
&lt;/h2&gt;

&lt;p&gt;The timing may be as interesting as the benchmark numbers. Google shipped 3.7 Flash only three weeks after 3.6 Flash, reinforcing an increasingly iterative approach to its workhorse models.&lt;/p&gt;

&lt;p&gt;The bigger story is economic: a model capable enough to code, use tools, process documents, and automate business tasks can matter more than another leaderboard leader if developers can run it at scale.&lt;/p&gt;

&lt;p&gt;The real test comes after the introductory price expires on &lt;strong&gt;January 1, 2027&lt;/strong&gt;. If teams keep 3.7 Flash in production because it completes enough work with few enough retries, this release will have mattered for reasons that have little to do with benchmark headlines.&lt;/p&gt;

&lt;p&gt;For now, Gemini 3.7 Flash looks like &lt;strong&gt;a cheaper workhorse moving closer to frontier capability—and making production-scale agents easier to justify.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Sources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/introducing-gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google — Introducing Gemini 3.7 Flash&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://deepmind.google/models/model-cards/gemini-3-7-flash/" rel="noopener noreferrer"&gt;Google DeepMind — Gemini 3.7 Flash Model Card&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.reuters.com/business/google-unveils-gemini-37-flash-ai-model-coding-agent-workflows-2026-08-13/" rel="noopener noreferrer"&gt;Reuters — Google unveils Gemini 3.7 Flash AI model for coding, agent workflows&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/google-launches-gemini-3-7-flash-three-weeks-after-3-6-with-50-introductory-pricing-mgns7" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>llmpricing</category>
      <category>gemini37flash</category>
      <category>geminiapi</category>
      <category>gemini37flashbenchmarks</category>
    </item>
    <item>
      <title>The Rise of AI Trading Among Retail Investors</title>
      <dc:creator>Pradeep Kumar</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:28:59 +0000</pubDate>
      <link>https://dev.to/pradeep_kumar_bc4e7e9f7ec/the-rise-of-ai-trading-among-retail-investors-2e0j</link>
      <guid>https://dev.to/pradeep_kumar_bc4e7e9f7ec/the-rise-of-ai-trading-among-retail-investors-2e0j</guid>
      <description>&lt;p&gt;On May 27, 2026, Robinhood let customers connect Claude, ChatGPT, and other AI agents straight to their trading accounts. The agents can watch markets, rebalance a portfolio, and place real trades, wrapped in guardrails like a dedicated account, spending limits, and a one-tap kill switch. &lt;a href="https://www.coindesk.com/markets/2026/05/27/robinhood-is-letting-ai-trade-for-you-so-you-don-t-have-to-keep-checking-the-markets" rel="noopener noreferrer"&gt;Robinhood built the feature&lt;/a&gt; on top of the Model Context Protocol, the same standard developers use to wire agents into any other tool.&lt;/p&gt;

&lt;p&gt;That single launch says a lot about where retail investing landed this year. AI trading isn't a hedge fund exclusive anymore. It's a toggle in a consumer app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers Behind the Shift
&lt;/h2&gt;

&lt;p&gt;The AI trading platform market was worth $11.2 billion in 2024. &lt;a href="https://www.grandviewresearch.com/industry-analysis/ai-trading-platform-market-report" rel="noopener noreferrer"&gt;Grand View Research&lt;/a&gt; puts it at $16.2 billion in 2026, on track for $33.5 billion by 2030 at a 20% annual growth rate.&lt;/p&gt;

&lt;p&gt;Retail adoption is keeping pace. A &lt;a href="https://www.investing.com/blog/how-retail-investors-are-using-ai-in-2026-339" rel="noopener noreferrer"&gt;March 2026 Investing.com survey&lt;/a&gt; of 938 American investors found 65% of AI users say the technology improved their market performance. Most of the same respondents still cross-check AI output against other sources before they act on it, so trust is growing but it isn't blind.&lt;/p&gt;

&lt;p&gt;The shift isn't only American. &lt;a href="https://www.precedenceresearch.com/ai-trading-platform-market" rel="noopener noreferrer"&gt;Precedence Research&lt;/a&gt; notes that Chinese retail investors have started leaning on tools like DeepSeek to sharpen their trading decisions, and expects Asia-Pacific to grow fastest as India and China add retail traders every quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Retail Investors Are Actually Using
&lt;/h2&gt;

&lt;p&gt;Three distinct layers have formed under the "AI trading" label. Each one asks for a different amount of technical comfort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Brokerage-native tools
&lt;/h3&gt;

&lt;p&gt;Robinhood shipped Cortex and Robinhood Strategies before Agentic Trading arrived, and the feature now serves the company's &lt;a href="https://news.bitcoin.com/robinhood-launches-ai-agent-trading-for-27-million-customers-options-and-crypto-next/" rel="noopener noreferrer"&gt;27 million funded customers&lt;/a&gt;. In India, Zerodha's no-code Streak platform plugs directly into its Kite terminal, letting users build and backtest rule-based strategies without writing a line of code, and &lt;a href="https://gyaniturtle.com/agentic-ai-investing-india-trading-basics/" rel="noopener noreferrer"&gt;SEBI-registered advisors like Jarvis Invest&lt;/a&gt; now run algorithmic rebalancing on real client assets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Third-party bot platforms
&lt;/h3&gt;

&lt;p&gt;Crypto-focused products sit a level down from brokerage features. 3Commas and Cryptohopper let traders run grid or dollar-cost-averaging bots without touching an API, trading some flexibility for a much shorter setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  API-first infrastructure
&lt;/h3&gt;

&lt;p&gt;This is the layer developers actually build on. &lt;a href="https://alpaca.markets/blog/alpaca-recognized-as-best-broker-for-algorithmic-trading-in-2026-by-brokerchooser/" rel="noopener noreferrer"&gt;Alpaca won BrokerChooser's 2026 award&lt;/a&gt; for Best Broker for Algorithmic Trading, and its &lt;a href="https://alpaca.markets/" rel="noopener noreferrer"&gt;Trading API ships official MCP servers&lt;/a&gt; so an agent running in Claude or ChatGPT can call the same endpoints that power live trading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your Own: The Developer Path
&lt;/h2&gt;

&lt;p&gt;Here's roughly how one of these agentic pipelines works end to end, guardrails included.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Market Data Feed] --&amp;gt; B[Signal / Model]
    B --&amp;gt; C{AI Agent Decision}
    C --&amp;gt;|Within limits| D[Guardrails Check]
    C --&amp;gt;|Flagged| E[Human Review]
    D --&amp;gt; F[Order Execution]
    E --&amp;gt; F
    F --&amp;gt; G[(Broker: Alpaca / Robinhood)]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The mechanics behind that diagram are almost boring now. &lt;code&gt;alpaca-py&lt;/code&gt;, &lt;a href="https://pypi.org/project/alpaca-py/" rel="noopener noreferrer"&gt;Alpaca's official Python SDK&lt;/a&gt;, reduces "fetch data, check a condition, place an order" to about 20 lines, and paper trading means none of it touches real money until you flip one flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.trading.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TradingClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.trading.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MarketOrderRequest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.trading.enums&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OrderSide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeInForce&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.data.historical&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StockHistoricalDataClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.data.requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StockBarsRequest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;alpaca.data.timeframe&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TimeFrame&lt;/span&gt;

&lt;span class="n"&gt;trading_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TradingClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paper&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StockHistoricalDataClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;bars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_stock_bars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;StockBarsRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;symbol_or_symbols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TimeFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;

&lt;span class="n"&gt;sma_20&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;last_close&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_close&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sma_20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MarketOrderRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OrderSide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BUY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_in_force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TimeInForce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DAY&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;trading_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;order&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 a skeleton for wiring up the API, not a strategy worth running. Pair it with &lt;a href="https://alpaca.markets/sdks/python/" rel="noopener noreferrer"&gt;FinRL for reinforcement learning experiments or Backtrader for backtesting&lt;/a&gt;, and a solo developer now has most of what a small quant desk had a decade ago.&lt;/p&gt;

&lt;p&gt;The gap between "have an idea" and "have a working bot" has basically closed. That's most of the reason retail AI trading grew so fast this year.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality Check
&lt;/h2&gt;

&lt;p&gt;Easy to build doesn't mean easy to profit from. The clearest evidence comes from Alpha Arena, a live benchmark from startup Nof1 that hands frontier AI models real money and lets them trade in public.&lt;/p&gt;

&lt;p&gt;In its first season, six models each traded $10,000 in crypto perpetual contracts from October 17 to November 3, 2025. By the end, &lt;a href="https://protos.com/llm-crypto-trading-contest-finds-llms-cant-trade-crypto/" rel="noopener noreferrer"&gt;ChatGPT was down $6,267, Gemini was down $5,671, Grok was down $4,531, and Claude Sonnet was down $3,081&lt;/a&gt;; only DeepSeek and Qwen3 Max finished in the green, up $489 and $2,232.&lt;/p&gt;

&lt;p&gt;A later round moved the same idea to US tech stocks, and &lt;a href="https://www.fa-mag.com/news/ai-bots-auditioning-for-wall-street-trading-are-mostly-losing-86902.html" rel="noopener noreferrer"&gt;Bloomberg reported&lt;/a&gt; the results didn't improve. Across 32 total contest outcomes, a model finished in profit only six times, and the group lost close to a third of its combined capital. Two models given the exact same prompt still traded wildly differently: one placed 158 trades, the other 1,418.&lt;/p&gt;

&lt;p&gt;Nof1 founder Jay Azhang put it simply: current models can't generate returns on their own, they need serious surrounding infrastructure just to have a shot. Doug Clinton, who runs the LLM-driven fund Intelligent Alpha, described the models as having "personalities that you have to manage almost like a human analyst," since the same prompt can leave one model bullish and another bearish for no clear reason.&lt;/p&gt;

&lt;p&gt;Prediction markets add a useful caveat here. &lt;a href="https://www.coindesk.com/tech/2026/03/15/ai-agents-are-quietly-rewriting-prediction-market-trading" rel="noopener noreferrer"&gt;CoinDesk reported in March 2026&lt;/a&gt; that only 7% to 13% of human traders on Polymarket turn a consistent profit, a genuinely low bar. Olas co-founder David Minarsch told the outlet his firm's Polystrat agent saw over 37% of its wallets finish positive in its first month live, though that number is the company's own claim about its own product, not an independent audit, a distinction worth holding onto in a space full of impressive self-reported figures.&lt;/p&gt;

&lt;p&gt;Hidden costs explain part of every automated strategy's underperformance too. A system placing dozens of trades a day accumulates fees and slippage fast enough to turn a solid gross return into a net loss, and a backtest that looks strong across years of historical data can still blow through its stop-loss once real conditions shift underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regulators Are Paying Attention
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.finra.org/rules-guidance/guidance/reports/2026-finra-annual-regulatory-oversight-report/gen-ai" rel="noopener noreferrer"&gt;FINRA's December 2025 oversight report&lt;/a&gt; added a dedicated GenAI section for the first time, flagging autonomous AI agents as their own risk category. The concerns are specific: agents acting without human validation, agents operating past their intended scope, and generative tools producing fake news or coordinated social posts built to look like real retail enthusiasm.&lt;/p&gt;

&lt;p&gt;The SEC is pointing the same direction. Its &lt;a href="https://www.innreg.com/blog/sec-guidance-on-ai" rel="noopener noreferrer"&gt;2026 exam priorities&lt;/a&gt; now expect firms to explain what their AI systems do, who supervises them, and how risks get caught before they compound.&lt;/p&gt;

&lt;p&gt;Robinhood addresses this directly in its own disclosures. The company &lt;a href="https://robinhood.com/us/en/newsroom/robinhood-is-now-open-to-agents/" rel="noopener noreferrer"&gt;states plainly that it doesn't control, supervise, monitor, or audit&lt;/a&gt; third-party AI agents once they're connected, and that customers assume all risk for orders those agents place.&lt;/p&gt;

&lt;p&gt;India has taken a more structured path. &lt;a href="https://www.businesstoday.in/markets/top-story/story/sebi-proposes-to-open-up-algo-trading-for-retail-investors-to-improve-market-integrity-457242-2024-12-13" rel="noopener noreferrer"&gt;SEBI released a draft circular in December 2024&lt;/a&gt; opening algorithmic trading to retail investors through exchange-approved broker APIs, and finalized the framework in February 2025 with every order tagged by a unique Algo-ID for the audit trail. It's a middle ground between banning automation outright and leaving it unregulated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Goes
&lt;/h2&gt;

&lt;p&gt;None of this makes AI trading a fad. The infrastructure is real, from broker APIs to MCP servers to no-code builders, and it's improving fast.&lt;/p&gt;

&lt;p&gt;What the 2026 data actually supports is narrower than the hype suggests. Even Nof1, the startup running Alpha Arena, is building its actual business around helping retail traders assemble their own agents rather than betting on a model that trades unsupervised. AI helps most as a research and execution layer, and the accounts that hold up tend to keep a human setting the boundaries instead of handing over the keys entirely.&lt;/p&gt;

&lt;p&gt;For developers, that's the more interesting problem to build for anyway. A system that surfaces a signal and explains its reasoning is a harder, more useful thing to ship than one that just fires off trades in the dark.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://zyvop.com/the-rise-of-ai-trading-among-retail-investors-g1c2z" rel="noopener noreferrer"&gt;ZyVOP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 For more articles like this, &lt;a href="https://zyvop.com/newsletter" rel="noopener noreferrer"&gt;subscribe to the ZyVOP newsletter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>python</category>
      <category>regulation</category>
      <category>fintech</category>
      <category>aitrading</category>
    </item>
  </channel>
</rss>
