<?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>Forem: Asaolu Elijah 🧙‍♂️</title>
    <description>The latest articles on Forem by Asaolu Elijah 🧙‍♂️ (@asaoluelijah).</description>
    <link>https://forem.com/asaoluelijah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171777%2F88e2ce8e-3d51-493d-8ff0-11687cf72c16.png</url>
      <title>Forem: Asaolu Elijah 🧙‍♂️</title>
      <link>https://forem.com/asaoluelijah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/asaoluelijah"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Tue, 19 May 2026 19:53:48 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/-42d</link>
      <guid>https://forem.com/asaoluelijah/-42d</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24" class="crayons-story__hidden-navigation-link"&gt;Why you must switch to a hybrid AI building model now&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/hackmamba"&gt;
            &lt;img alt="Hackmamba logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4237%2Ffc7e54fa-d61f-400a-8b5d-7be8253c8f12.jpeg" class="crayons-logo__image" width="800" height="800"&gt;
          &lt;/a&gt;

          &lt;a href="/asaoluelijah" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171777%2F88e2ce8e-3d51-493d-8ff0-11687cf72c16.png" alt="asaoluelijah profile" class="crayons-avatar__image" width="540" height="540"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/asaoluelijah" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Asaolu Elijah 🧙‍♂️
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Asaolu Elijah 🧙‍♂️
                
              
              &lt;div id="story-author-preview-content-3703461" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/asaoluelijah" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171777%2F88e2ce8e-3d51-493d-8ff0-11687cf72c16.png" class="crayons-avatar__image" alt="" width="540" height="540"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Asaolu Elijah 🧙‍♂️&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/hackmamba" class="crayons-story__secondary fw-medium"&gt;Hackmamba&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 19&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24" id="article-link-3703461"&gt;
          Why you must switch to a hybrid AI building model now
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Why you must switch to a hybrid AI building model now</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Tue, 19 May 2026 19:53:38 +0000</pubDate>
      <link>https://forem.com/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24</link>
      <guid>https://forem.com/hackmamba/why-you-must-switch-to-a-hybrid-ai-building-model-now-1k24</guid>
      <description>&lt;p&gt;There is a big difference between generating code and delivering software. You have likely seen the demos where someone types a prompt and a screen appears, so it looks like the hard work is over. But when you try to turn that demo into a real business product, progress stops. The app that looked ready suddenly turns into weeks of meetings about security, integrations, ownership and infrastructure. This is the major gap between a prototype and a V1 Alpha.&lt;/p&gt;

&lt;p&gt;A prototype, which is what most AI tools generate, is a visual argument. A V1 Alpha, on the other hand, is an operational commitment. It is software that can be shipped, secured, owned and extended. The mistake many teams made was treating these as the same category of work. That assumption is now breaking down in the market.&lt;/p&gt;

&lt;p&gt;Teams are &lt;a href="https://www.reddit.com/r/aipromptprogramming/comments/1nidyif/ai_can_write_90_of_your_code_but_its_not_making/" rel="noopener noreferrer"&gt;starting to recognize&lt;/a&gt; these gaps, which explains a clear shift in decision-making. Leaders are no longer impressed by generation speed alone if it does not lead to a usable outcome. They are starting to pay for certainty plus speed, meaning the ability to reach a working result quickly without inheriting delivery risk or long setup cycles.&lt;/p&gt;

&lt;p&gt;Still, achieving that certainty and speed depends on choosing the right delivery model. To help you choose the right path, this article compares the three dominant delivery models on speed, cost and risk. We will explore why AI-only projects often lack ownership and why traditional shops are too slow for modern needs. Then, we will demonstrate how the hybrid model bridges this gap to deliver verifiable software immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing the three software delivery models
&lt;/h2&gt;

&lt;p&gt;Here are the three different delivery models that teams use when developing software today.&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.amazonaws.com%2Fuploads%2Farticles%2F5sa55o8qmsyi0i6pm1ql.png" 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.amazonaws.com%2Fuploads%2Farticles%2F5sa55o8qmsyi0i6pm1ql.png" alt="A side-by-side comparison of the workflow, timeline, and final output for the three software delivery models" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model A: AI builder only&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this model, an internal team uses an AI coding tool directly. The workflow is simple. Someone opens a tool like Lovable or Replit and types a prompt describing a feature, such as a dashboard with a sales chart and user login. Within minutes, the tool produces a clean and working UI.&lt;/p&gt;

&lt;p&gt;The limitation shows up when the application needs to interact with real systems. As soon as the team tries to connect the app to a production database, authentication provider or internal API, gaps appear, especially in areas like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error handling and edge cases&lt;/li&gt;
&lt;li&gt;Authentication and access control&lt;/li&gt;
&lt;li&gt;Data contracts and schema validation&lt;/li&gt;
&lt;li&gt;Environment and deployment configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated code looks correct, but does not behave like owned software. There is also no clean handoff point. The AI returns syntax and structure, but the responsibility for making it production-ready falls entirely on the internal team. Many teams discover that turning the demo into a product requires rewriting large portions of the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model B: The traditional dev shop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the traditional service model that prioritizes risk management through rigorous processes. It assumes that the safest way to build software is to define every requirement before writing a line of code. The engagement usually begins with a heavy upfront phase focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discovery workshops and stakeholder interviews&lt;/li&gt;
&lt;li&gt;Detailed requirement documents and specifications&lt;/li&gt;
&lt;li&gt;Architecture diagrams and technical planning&lt;/li&gt;
&lt;li&gt;Approval cycles and sign-offs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might spend the first three months paying for meetings and documents, feeling secure because of the paper trail. However, when the agency finally delivers the software in month four, you often discover that the agreed-upon vision in the PDF does not actually feel right in the browser. At that point, changes are possible, but they are slow and expensive. Teams pay for safety early, but clarity arrives late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model C: Hybrid AI delivery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The hybrid model changes the order of delivery. It replaces fragile demos and long preparation cycles with a working V1 Alpha delivered in days.&lt;/p&gt;

&lt;p&gt;In this model, tools like &lt;a href="https://bit.cloud/products/hope-ai" rel="noopener noreferrer"&gt;Hope AI&lt;/a&gt; accelerate construction, while experts ensure the software is properly structured. Rather than producing a single large application, the system builds independent and reusable components, such as authentication modules, data connectors and core workflows. Compared to the previous models, this approach works well because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Produces real, running software instead of static documents or throwaway demos&lt;/li&gt;
&lt;li&gt;Integrates with production systems early, reducing late-stage surprises&lt;/li&gt;
&lt;li&gt;Applies structure, testing and access control from the start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each component is designed to deliver tests and documentation, which makes the V1 Alpha inspectable, maintainable and safe to hand off to an internal team.&lt;/p&gt;

&lt;p&gt;To better understand how these models differ in practice, let's compare how each one answers the questions decision makers care about. These questions map directly to speed, cost, risk and clarity.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stakeholder question&lt;/th&gt;
&lt;th&gt;Model A: AI builder only&lt;/th&gt;
&lt;th&gt;Model B: Traditional dev shop&lt;/th&gt;
&lt;th&gt;Model C: Hybrid AI delivery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;When do I see something real?&lt;/td&gt;
&lt;td&gt;Minutes (fragile prototype)&lt;/td&gt;
&lt;td&gt;Months (after discovery)&lt;/td&gt;
&lt;td&gt;Days (Verified V1 Alpha)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does "done" mean?&lt;/td&gt;
&lt;td&gt;Syntax is returned.&lt;/td&gt;
&lt;td&gt;Contract scope is fulfilled.&lt;/td&gt;
&lt;td&gt;Screens and logic and tests are verified.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do we scale?&lt;/td&gt;
&lt;td&gt;Hard to refactor; usually a start over&lt;/td&gt;
&lt;td&gt;Slow, manual and expensive&lt;/td&gt;
&lt;td&gt;Add/update components independently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who owns accountability?&lt;/td&gt;
&lt;td&gt;The prompter&lt;/td&gt;
&lt;td&gt;The Agency (until handoff)&lt;/td&gt;
&lt;td&gt;Shared (Service builds V1 and Stakeholder decides V2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What happens after the demo?&lt;/td&gt;
&lt;td&gt;Likely rebuild for production&lt;/td&gt;
&lt;td&gt;Expensive maintenance retainers&lt;/td&gt;
&lt;td&gt;Assets ready to deploy or iterate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope control&lt;/td&gt;
&lt;td&gt;Endless prompting&lt;/td&gt;
&lt;td&gt;Change orders&lt;/td&gt;
&lt;td&gt;Purchase specific Expert Hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost predictability&lt;/td&gt;
&lt;td&gt;Low (time sink)&lt;/td&gt;
&lt;td&gt;Low (estimates slip)&lt;/td&gt;
&lt;td&gt;High (Fixed start and hourly blocks)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Looking at the operational realities of these three paths, it is clear that the hybrid model offers a more balanced outcome than the traditional and AI-only models.&lt;/p&gt;

&lt;p&gt;That conclusion, however, only describes the result. To understand why the hybrid model works, it helps to examine where the other two break down operationally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the traditional and AI-only models break
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The AI builder flaw: The missing owner&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The AI-only model usually works right up until someone asks a simple question: "Who is responsible for this?"&lt;/p&gt;

&lt;p&gt;Unlike traditional software projects, there is no natural transition from creation to ownership. The system appears complete, but responsibility never formally transfers, leaving the work suspended between a demo and a product. Even at the individual level, users often stall immediately after prompting because they cannot explain or defend the code they just built. This creates a fundamental disconnect where the person is the prompter while the AI is the architect, and neither is truly the owner.&lt;/p&gt;

&lt;p&gt;Another reason an AI-only workflow fails is that it treats software as a visual task rather than an operational one. Within a real organization, software must survive an ecosystem of existing security standards, data privacy laws and technical debt. Because the AI has no knowledge of these constraints, and the prompter lacks the depth to bridge them, the model collapses the moment an official owner is required to vouch for the integrity of the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The dev shop flaw: The slow start&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The traditional model fails because it separates spending from seeing. It starts with months of planning and meetings, which feels safe but is actually high risk. During this time, you are paying for a plan instead of a working product.&lt;/p&gt;

&lt;p&gt;Because you are looking at documents instead of a live app, you have no way to verify if the vision is correct. You are essentially flying blind while the budget burns. By the time the software is finally delivered months later, you have usually spent too much money to change course. You are stuck with what was built, even if it no longer fits your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mechanism that makes hybrid delivery work
&lt;/h2&gt;

&lt;p&gt;The core mechanism behind hybrid delivery is component-level isolation. It breaks the system into independent, reusable units that teams can inspect and adjust without introducing instability elsewhere.&lt;/p&gt;

&lt;p&gt;This model reduces uncertainty by flipping when verification happens. Instead of validating late, it validates early. It uses AI to accelerate construction while enforcing structured output. Features are generated as reusable components with documentation and tests. Experts review the system continuously to keep it coherent and maintainable.&lt;/p&gt;

&lt;p&gt;Additionally, since the output is production-grade from the beginning, the organization is not locked into a single vendor. Once the V1 Alpha is delivered, there is a clear decision point. The internal team can take ownership of the repository immediately, or the same team can continue execution using scoped expert hours.&lt;/p&gt;

&lt;p&gt;Here's a typical workflow it follows to achieve that:&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.amazonaws.com%2Fuploads%2Farticles%2Fmxbtd8ni3lhx074urxun.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fmxbtd8ni3lhx074urxun.png" alt="The Hybrid Workflow: From vision to a verifiable V1 Alpha and strategic handoff." width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define vision:&lt;/strong&gt; The requirement is provided, such as a Figma design or technical spec.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI augmented construction:&lt;/strong&gt; Experts use Hope AI to generate the application by creating verified and reusable bits rather than messy raw code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery of V1 Alpha:&lt;/strong&gt; Within days, the initial result is received. This is a functional V1 Alpha where screens and logic are verifiable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The gap assessment:&lt;/strong&gt; The team immediately identifies what is missing, usually requiring specific expert hours to handle tweaks, integrations and polish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strategic handoff:&lt;/strong&gt; The stakeholder decides whether to take ownership of the code or retain experts for further execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The hybrid software delivery model structures the engagement as a safe test and moves validation from month three to day three, allowing leadership to confirm viability before committing significant resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;If the project is a demo, then AI-only builders are fine. They are fast and free, and it does not matter if the code breaks under pressure. If the project is a product with users, risk and accountability, then you need a delivery model that produces an inspectable baseline early. That is the hybrid model.&lt;/p&gt;

&lt;p&gt;Projects requiring massive legacy overhauls may still find comfort in traditional dev shops. However, new products that need to exist in the real world, with real users, real security and real timelines, require a different approach. Waiting six months to see if an idea works is not affordable, nor is inheriting a broken AI demo.&lt;/p&gt;

&lt;p&gt;Bit Cloud delivers a V1 Alpha in days rather than months. For teams looking to build with AI while maintaining delivery accountability, the hybrid model is becoming the practical default. If you have a vision that needs to be tested in the real world, start the hybrid process with &lt;a href="https://bit.cloud/products/hope-ai" rel="noopener noreferrer"&gt;Hope AI on Bit Cloud&lt;/a&gt; to get your V1 Alpha today.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The AI stack every developer will depend on in 2026</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Tue, 19 May 2026 19:53:30 +0000</pubDate>
      <link>https://forem.com/hackmamba/the-ai-stack-every-developer-will-depend-on-in-2026-40ga</link>
      <guid>https://forem.com/hackmamba/the-ai-stack-every-developer-will-depend-on-in-2026-40ga</guid>
      <description>&lt;p&gt;The past few years have been the era of AI copilots. Tools like Cursor and Claude Code showed what happens when intelligence is integrated directly into a developer's workflow. They can generate and refactor hundreds of lines of code in seconds. But teams that use them at scale also see their limits.&lt;/p&gt;

&lt;p&gt;These tools are good at producing output but weak at continuity. They forget context, repeat past mistakes and aren't deeply integrated across the development pipeline. Their intelligence stops at the editor instead of extending into planning, testing and deployment. By 2026, that limitation is expected to fade with the rise of new frameworks and orchestration tools built for continuity.&lt;/p&gt;

&lt;p&gt;From next year, the differentiator will not be model size. It will depend on whether your AI stack has persistent memory, reusable artifacts, versioning and orchestrated workflows that keep systems stable after the first prompt.&lt;/p&gt;

&lt;p&gt;This article will explore the AI stack of 2026, drawing from current research, developer trends and early infrastructure experiments. You'll see how each stack layer fits together, the technologies worth exploring around each one and what steps you can take as a developer to prepare for the shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 AI stack at a glance
&lt;/h2&gt;

&lt;p&gt;Before diving into each layer, here's a quick overview of how the AI stack fits together and what role each part plays.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example technologies&lt;/th&gt;
&lt;th&gt;Key trend in 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Composable models&lt;/td&gt;
&lt;td&gt;Combine specialized models for different tasks&lt;/td&gt;
&lt;td&gt;vLLM, Replicate, Ollama, LangChain, CrewAI&lt;/td&gt;
&lt;td&gt;Model orchestration replaces single-model workflows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP and interoperability&lt;/td&gt;
&lt;td&gt;Connect models and tools across environments&lt;/td&gt;
&lt;td&gt;Model Context Protocol SDK, AutoGen&lt;/td&gt;
&lt;td&gt;A shared context protocol becomes the default way systems coordinate.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistent memory components&lt;/td&gt;
&lt;td&gt;Maintain long-term context and recall&lt;/td&gt;
&lt;td&gt;MemOS, Pinecone, Weaviate, Milvus, Chroma&lt;/td&gt;
&lt;td&gt;Memory becomes a durable, queryable runtime layer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Versioned artifact registry&lt;/td&gt;
&lt;td&gt;Track and version AI-generated outputs&lt;/td&gt;
&lt;td&gt;Hope AI, Windsurf Cascade Memory&lt;/td&gt;
&lt;td&gt;Versioned artifacts become the standard output of AI systems.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human-AI collaboration interface&lt;/td&gt;
&lt;td&gt;Connect developers directly with AI systems&lt;/td&gt;
&lt;td&gt;Cursor, Windsurf, Claude Code&lt;/td&gt;
&lt;td&gt;IDEs evolve into AI-first workspaces that blend memory and tooling.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With that overview in mind, let's start with the foundation of the stack and look at how composable models are reshaping AI development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Composable models
&lt;/h2&gt;

&lt;p&gt;In 2025, most AI workflows still depend on a single model. You send a prompt and get a response, and the interaction ends there. The models are powerful, but they work in isolation. Some platforms now let you swap models, such as switching from Gemini to Claude in the same interface, but it's still a manual process. You pick the model yourself; the platform doesn't yet decide which one fits the task best.&lt;/p&gt;

&lt;p&gt;By 2026, that's expected to change. AI workflows will begin to use semantic routing, where an orchestrator automatically selects the best model or tool for each step. A typical workflow could look like using ChatGPT-5 for planning, Gemini for reasoning and Claude for fast code generation.&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.amazonaws.com%2Fuploads%2Farticles%2Fu0i3carxskq4e4z1j81k.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fu0i3carxskq4e4z1j81k.png" alt="Composable Model Architecture Overview" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown in the image above, models will become composable components, working together like microservices in a distributed system. This shift is already in motion, and the tools driving innovation in this space include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/vllm-project/vllm" rel="noopener noreferrer"&gt;vLLM&lt;/a&gt;: Focuses on efficient multi-model serving and inference optimization&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://replicate.com/" rel="noopener noreferrer"&gt;Replicate&lt;/a&gt;: Provides APIs for integrating diverse hosted models into shared pipelines&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ollama/ollama" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;: Enables developers to run open-source models locally for testing and experimentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt; and &lt;a href="https://www.crewai.com/" rel="noopener noreferrer"&gt;CrewAI&lt;/a&gt;: Orchestration frameworks evolving toward intelligent coordination across models and workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scaling model size alone has already shown diminishing returns in many workflows. Research and production experience both show that context handling, memory and structured workflows drive more value than simply adding parameters. Composable models are the first indication that we are transitioning from a single, monolithic model approach to a stack-based approach.&lt;/p&gt;

&lt;p&gt;From next year, intelligence will no longer reside in a single model but will flow across a network of interconnected systems, each optimized for a specific task.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP and interoperability
&lt;/h2&gt;

&lt;p&gt;Once models become composable, the next challenge is getting them to work together across different environments. The Model Context Protocol (MCP) is already making its mark in this area. MCP defines a shared standard for how AI systems exchange context, capabilities and data.&lt;/p&gt;

&lt;p&gt;By 2026, MCP will become the backbone of system-level interoperability. Instead of just linking models, it will connect entire development environments. A local build agent could coordinate with a cloud-hosted reasoning model, pull stored memory from a shared vector database and push validated outputs directly to a CI pipeline, all through a unified context layer.&lt;/p&gt;

&lt;p&gt;An MCP-aware IDE will also sync project state, model preferences and access tokens across tools like Cursor, Replit and GitHub Codespaces. Context will move with the task across systems, not just across models. Multiple technologies and resources are already taking shape around this space, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/docs/sdk" rel="noopener noreferrer"&gt;Model Context Protocol SDK&lt;/a&gt;: The official toolkit for building MCP clients and servers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pimzino/spec-workflow-mcp" rel="noopener noreferrer"&gt;Spec-workflow-mcp&lt;/a&gt;: A workflow-oriented project showing how MCP integrates with developer operations and dashboards&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt; and &lt;a href="https://microsoft.github.io/autogen/stable//index.html" rel="noopener noreferrer"&gt;AutoGen&lt;/a&gt;: Frameworks beginning to adopt MCP-style orchestration to connect models, tools and agents across clouds and runtimes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers, this trend will shift AI from tool-by-tool integration to a shared context bus. By 2026, composable models and their orchestration layers will use MCP-like protocols to move tasks and memory between agents, CI systems and runtime environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistent memory components
&lt;/h2&gt;

&lt;p&gt;Memory is still one of the weakest components of large language models. Even the latest models still rely on fixed context windows and don't have real memory. They can process huge amounts of text and give the feeling of continuity, but once a session ends, everything disappears. Each new interaction starts from zero, and the only way to maintain context is to resend past information, which is expensive.&lt;/p&gt;

&lt;p&gt;This limitation comes from how &lt;a href="https://aws.plainenglish.io/how-memory-works-in-transformer-llms-and-why-long-term-memory-is-difficult-5edd4ef5e90b" rel="noopener noreferrer"&gt;transformer-based models&lt;/a&gt; work. They read and process the context you give them at a moment, but don't actually store anything. There is no persistent state, only temporary attention over recent tokens. What we call AI memory today is mostly clever caching that looks like recall but isn't.&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.amazonaws.com%2Fuploads%2Farticles%2Ffrytffp61z1ewranm0tm.png" 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.amazonaws.com%2Fuploads%2Farticles%2Ffrytffp61z1ewranm0tm.png" alt="Persistent Memory Components Architecture Overview" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is beginning to change. Persistent memory is starting to form its own runtime layer, separate from the model. Instead of reloading context on every call, systems are starting to use external stores that track what a model learns, produces and references. These stores are structured, queryable and shareable across agents, turning context into a durable state rather than a disposable input.&lt;/p&gt;

&lt;p&gt;By 2026, memory will act like a runtime layer. Models will read and write to persistent memory graphs that store embeddings, reasoning traces, dependencies and artifacts. Agents will build on existing state instead of recreating the same logic from scratch.&lt;/p&gt;

&lt;p&gt;Technologies leading this shift include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2507.03724" rel="noopener noreferrer"&gt;MemOS&lt;/a&gt;: A prototype architecture for persistent, composable and queryable agent memory&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pinecone.io/" rel="noopener noreferrer"&gt;Pinecone&lt;/a&gt;: Expanding beyond vector storage to handle metadata, relationships and versioned embeddings&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://milvus.io/" rel="noopener noreferrer"&gt;Milvus&lt;/a&gt;: Optimized for large-scale, distributed memory operations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lancedb.com/" rel="noopener noreferrer"&gt;LanceDB&lt;/a&gt; and &lt;a href="https://www.trychroma.com/" rel="noopener noreferrer"&gt;Chroma&lt;/a&gt;: Lightweight local layers for fast recall and offline persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other notable mentions include user-facing tools such as &lt;a href="https://help.openai.com/en/articles/10169521-projects-in-chatgpt" rel="noopener noreferrer"&gt;ChatGPT Projects&lt;/a&gt; and &lt;a href="https://www.perplexity.ai/help-center/en/articles/10354769-what-is-a-thread" rel="noopener noreferrer"&gt;Perplexity Threads&lt;/a&gt;, where context now persists across sessions instead of resetting to zero.&lt;/p&gt;

&lt;p&gt;These tools represent a transition from fixed context windows to memory graphs that store embeddings alongside reasoning traces, dependencies and results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioned artifact registry
&lt;/h2&gt;

&lt;p&gt;As AI systems gain memory, the next challenge is traceability. When a model generates a file, it's often unclear which version of the model produced it, what context it used or how that output has evolved. This lack of lineage makes debugging, testing and reuse difficult.&lt;/p&gt;

&lt;p&gt;That gap is beginning to close. From next year, AI-generated code, documentation and data will be treated as versioned artifacts, with metadata describing their source model, parameters and compatibility. Registries will track how these artifacts change over time, making it easy to audit, reuse and refactor them like open-source libraries.&lt;/p&gt;

&lt;p&gt;Each artifact will carry metadata such as persistent IDs and namespaces, version history, capabilities, compatibility notes, dependency graphs and test and validation results, including the inputs used to check it and the conditions where it's safe to reuse.&lt;/p&gt;

&lt;p&gt;A new generation of platforms forming around this idea includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bit.cloud/products/hope-ai" rel="noopener noreferrer"&gt;Hope AI (by Bit Cloud)&lt;/a&gt;: An AI development agent that turns natural language into production-ready applications and manages a registry of reusable components with versioned capabilities, tests, docs, dependency graphs and a global memory of previous builds&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.windsurf.com/windsurf/cascade/memories" rel="noopener noreferrer"&gt;Windsurf's Cascade Memory&lt;/a&gt;: A feature in the Windsurf editor that links AI outputs to their generative history, blending persistent memory with artifact management for better traceability and reuse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git solved collaboration for human-written code. The 2026 AI stack needs the same for AI-generated artifacts, and Bit Cloud is building that layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human-AI collaboration interface
&lt;/h2&gt;

&lt;p&gt;The top layer of the stack is where humans and AI systems meet. AI coding tools such as &lt;a href="https://cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;, &lt;a href="https://windsurf.com/" rel="noopener noreferrer"&gt;Windsurf&lt;/a&gt; and &lt;a href="https://www.claude.com/product/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; are already making waves here, analyzing project files, generating multi-file implementations, explaining reasoning and even drafting pull requests.&lt;/p&gt;

&lt;p&gt;Still, they mostly operate within the local workspace. They understand your codebase but rarely connect to the broader system context. Once code leaves the IDE, the AI often loses awareness of how it fits into your build process. That's the gap the next generation of environments is aiming to close.&lt;/p&gt;

&lt;p&gt;By 2026, IDEs will be less of a text editor and more of a control plane for the AI stack. They'll surface memory graphs, orchestration flows and artifact history alongside the code itself. A developer might inspect how an agent arrived at a decision, which dataset or model it used and how its output evolved, all from within the same interface.&lt;/p&gt;

&lt;p&gt;The next wave of IDEs will also track code beyond the local workspace. They'll follow it through build, runtime and deployment so the AI keeps the bigger picture even after changes leave the editor.&lt;/p&gt;

&lt;p&gt;As all these layers come together, your role as a developer will evolve along with the tools you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this shift means for developers
&lt;/h2&gt;

&lt;p&gt;Over the next few years, your day-to-day work will undergo visible changes. You will still write code, but you will also take on new tasks that come with AI-native development. You will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review AI-generated artifacts in pull requests and treat them as first-class components&lt;/li&gt;
&lt;li&gt;Decide when to reuse an existing artifact instead of regenerating one&lt;/li&gt;
&lt;li&gt;Debug memory graphs, dependency links and reasoning traces when something breaks&lt;/li&gt;
&lt;li&gt;Manage persistent memory as part of the normal workflow&lt;/li&gt;
&lt;li&gt;Choose orchestration engines the same way teams choose CI systems&lt;/li&gt;
&lt;li&gt;Curate shared component libraries that span multiple projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For team leads, practices such as versioning AI artifacts and using orchestration frameworks are already becoming standard across AI infrastructure teams. Adopting these habits early will make the move toward AI-native development much smoother as the ecosystem matures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking forward
&lt;/h2&gt;

&lt;p&gt;From next year, most teams will move from single-model prompting to composable models, managing memory graphs and curating AI artifacts as part of their core engineering workflow. The teams that treat memory, reuse and versioning as infrastructure will move faster and ship more stable systems.&lt;/p&gt;

&lt;p&gt;Platforms like &lt;a href="https://bit.cloud" rel="noopener noreferrer"&gt;Bit Cloud&lt;/a&gt; and &lt;a href="https://bit.cloud/products/hope-ai" rel="noopener noreferrer"&gt;Hope AI&lt;/a&gt; are early examples of this stack in action, combining composability, global memory and artifact versioning into a production-grade workflow.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Web scraping for AI agents: How to give your agents web access</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Mon, 13 Apr 2026 19:28:45 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/web-scraping-for-ai-agents-how-to-give-your-agents-web-access-4577</link>
      <guid>https://forem.com/asaoluelijah/web-scraping-for-ai-agents-how-to-give-your-agents-web-access-4577</guid>
      <description>&lt;p&gt;AI agents are only as useful as the information they can act on. A reasoning model with a January knowledge cutoff can't tell you today's pricing, yesterday's news, or what your competitor just changed on their homepage. Giving your agent a way to reach out and pull fresh data from the web is how you fix that.&lt;/p&gt;

&lt;p&gt;Web scraping is how you do that. This guide walks through how it works, what breaks, and how to wire it cleanly into an AI agent workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agents need live web access
&lt;/h2&gt;

&lt;p&gt;Most LLMs are trained once and frozen. They know a lot, but that knowledge has an expiry date. This creates a fundamental problem for agents doing anything time-sensitive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;research agent&lt;/strong&gt; summarizing a competitor's product page will surface stale pricing.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;lead generation agent&lt;/strong&gt; building contact lists from directories misses companies founded last month.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;news monitoring agent&lt;/strong&gt; trained on data from six months ago isn't monitoring anything.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;price tracking agent&lt;/strong&gt; with no live feed is just guessing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Equipping your agent with a tool call that fetches current HTML, parses it intelligently, and returns structured data is how you solve this.&lt;/p&gt;

&lt;h2&gt;
  
  
  What scraping looks like in an agent loop
&lt;/h2&gt;

&lt;p&gt;In practice, scraping fits into an agent's tool-use loop the same way a database query or API call does. The agent decides it needs information from a URL, calls the scraping tool, gets back structured data, and continues reasoning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent needs: "What's the current price of product X?"
  → calls scrapeUrl(url, prompt)
  → gets back: { "name": "Product X", "price": 49.99, "currency": "USD" }
  → continues: "The price is $49.99, which is $5 lower than last week..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow is also represented in the diagram below:&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.amazonaws.com%2Fuploads%2Farticles%2Fb3e7xauzcanpzqwhz5zw.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fb3e7xauzcanpzqwhz5zw.png" alt="What scraping looks like in an agent loop" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key design question is: what does &lt;code&gt;scrapeUrl&lt;/code&gt; actually do under the hood?&lt;/p&gt;

&lt;h2&gt;
  
  
  Different scraping approaches
&lt;/h2&gt;

&lt;p&gt;There are a few ways to implement web access for an agent. They sit on a spectrum of complexity vs. reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raw HTTP + HTML parsing
&lt;/h3&gt;

&lt;p&gt;The simplest approach: fetch the URL with &lt;code&gt;fetch&lt;/code&gt;, parse the HTML with a library like Cheerio, extract what you need with selectors.&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cheerio&lt;/span&gt;&lt;span class="dl"&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;res&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User-Agent&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="s2"&gt;Mozilla/5.0&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;text&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;The problem:&lt;/strong&gt; Most modern websites don't return meaningful HTML on the first HTTP request. They're JavaScript-rendered. The above returns a shell. The content loads after JS executes. You'll also get blocked quickly with no proxy rotation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Headless browsers
&lt;/h3&gt;

&lt;p&gt;Tools like Playwright and Puppeteer launch a real browser, wait for JS to execute, then let you extract content. More reliable for modern sites.&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;chromium&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="s2"&gt;playwright&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;browser&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;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&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;page&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForLoadState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;networkidle&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;content&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;The problem:&lt;/strong&gt; This is expensive to run at scale. Infrastructure, browser pools, proxy management, and CAPTCHA handling all become your problem. And sophisticated anti-bot systems will still block you based on browser fingerprinting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scraping APIs
&lt;/h3&gt;

&lt;p&gt;The third option: delegate all of that to a purpose-built API. You send a URL and a description of what you want. The API handles browser automation, proxy rotation, CAPTCHA solving, and returns clean structured data.&lt;/p&gt;

&lt;p&gt;For agents, this is almost always the right call. You get a simple async interface, reliable results, and you're not managing headless browser infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real challenges (and why they matter for agents)
&lt;/h2&gt;

&lt;p&gt;Before picking an approach, understand what actually breaks in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Anti-bot detection:&lt;/strong&gt; IP rate limiting, CAPTCHA challenges, browser fingerprinting. If your agent scrapes the same site repeatedly, naive implementations get blocked fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JavaScript-rendered content:&lt;/strong&gt; Most product pages, social feeds, and dashboards render content after the initial HTML loads. Raw HTTP fetches get empty shells.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unstructured output:&lt;/strong&gt; Raw HTML or even extracted text isn't what your agent wants. Agents reason better over &lt;code&gt;{"price": 49.99}&lt;/code&gt; than over a wall of text that &lt;em&gt;contains&lt;/em&gt; the price somewhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Async workflows:&lt;/strong&gt; Scraping takes time (seconds, not milliseconds). Your agent can't block waiting for a result. You need job submission, polling, and async result handling baked in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scale:&lt;/strong&gt; If your agent processes 100 leads at a time, you need batch processing. Running 100 sequential scrape calls is slow and fragile.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What agent-ready scraping looks like
&lt;/h2&gt;

&lt;p&gt;Here's what the ideal scraping tool looks like from an agent's perspective:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Natural language prompts:&lt;/strong&gt; The agent describes what it wants, not how to get it. &lt;code&gt;"Extract the job title, company, and salary range"&lt;/code&gt; rather than a CSS selector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured JSON output:&lt;/strong&gt; Returns a typed object matching a schema the agent defines. No parsing, no regex, no string manipulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async with polling:&lt;/strong&gt; Submit a job, get a job ID, poll for results. Non-blocking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy and anti-bot handling built in:&lt;/strong&gt; The agent doesn't care about IP rotation. That's infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch support:&lt;/strong&gt; Submit 50 URLs at once, get 50 results back.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's build this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Implementation
&lt;/h2&gt;

&lt;p&gt;The following examples use &lt;a href="https://spidra.io" rel="noopener noreferrer"&gt;Spidra&lt;/a&gt;, an API built specifically for this pattern: browser automation, proxy rotation, CAPTCHA solving, and AI-powered extraction in one endpoint. The concepts translate to any scraping API with similar capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Get an API key from &lt;a href="https://app.spidra.io" rel="noopener noreferrer"&gt;app.spidra.io&lt;/a&gt; → Settings → API Keys.&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.amazonaws.com%2Fuploads%2Farticles%2F144dlx9a0gbb3h0rfgbe.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F144dlx9a0gbb3h0rfgbe.jpg" alt="API Key on Spidra dashboard" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base URL:&lt;/strong&gt; &lt;code&gt;https://api.spidra.io/api&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; &lt;code&gt;x-api-key&lt;/code&gt; header on every request.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 1: Simple scrape tool for an agent
&lt;/h3&gt;

&lt;p&gt;The pattern is always the same: submit a job, get a &lt;code&gt;jobId&lt;/code&gt;, poll until complete.&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-api-key&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;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.spidra.io/api&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;HEADERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&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="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useProxy&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="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&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;res&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;fetch&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;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/scrape`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&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;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&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;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jobId&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;status&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;fetch&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;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/scrape/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobId&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="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;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&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="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3000&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;Now your agent has a clean tool call:&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;result&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://news.ycombinator.com&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="s2"&gt;List the top 5 stories with title, points, and comment count&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="s2"&gt;stories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;stories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&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="s2"&gt;title&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="s2"&gt;points&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="s2"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;string&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="s2"&gt;null&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="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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// result.stories → [{ title, points, comments, url }, ...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent gets back a typed list it can iterate, filter, and reason over. No parsing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2: Structured output with JSON schema
&lt;/h3&gt;

&lt;p&gt;The schema field is the most important feature for agent use. Instead of getting unpredictable text, you define the exact shape of the response and the API enforces it.&lt;/p&gt;

&lt;p&gt;Here's a job listing extractor:&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;result&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://jobs.example.com/senior-engineer&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="s2"&gt;Extract all details about this job listing.&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="s2"&gt;title&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="s2"&gt;company&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="s2"&gt;remote&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;string&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="s2"&gt;null&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;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;boolean&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="s2"&gt;null&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;salary_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;number&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="s2"&gt;null&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;salary_max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;number&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="s2"&gt;null&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;employment_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&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="s2"&gt;string&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="s2"&gt;null&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;enum&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="s2"&gt;full_time&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="s2"&gt;part_time&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="s2"&gt;contract&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&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="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;// Guaranteed shape: fields in `required` always present, nullable where marked&lt;/span&gt;
&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   title: "Senior Engineer",&lt;/span&gt;
&lt;span class="c1"&gt;//   company: "Acme Corp",&lt;/span&gt;
&lt;span class="c1"&gt;//   location: "Austin, TX",&lt;/span&gt;
&lt;span class="c1"&gt;//   remote: true,&lt;/span&gt;
&lt;span class="c1"&gt;//   salary_min: 140000,&lt;/span&gt;
&lt;span class="c1"&gt;//   salary_max: 180000,&lt;/span&gt;
&lt;span class="c1"&gt;//   employment_type: "full_time",&lt;/span&gt;
&lt;span class="c1"&gt;//   skills: ["TypeScript", "React", "AWS"]&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two rules worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fields in &lt;code&gt;required&lt;/code&gt; always appear, as &lt;code&gt;null&lt;/code&gt; if the data isn't found.&lt;/li&gt;
&lt;li&gt;Optional fields are omitted entirely if unavailable.&lt;/li&gt;
&lt;li&gt;Mark anything that might be missing as &lt;code&gt;["type", "null"]&lt;/code&gt; to avoid surprises.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example 3: Crawling an entire site
&lt;/h3&gt;

&lt;p&gt;Sometimes your agent doesn't know which pages to scrape. It needs to discover them. The &lt;a href="https://docs.spidra.io/features/crawling" rel="noopener noreferrer"&gt;crawl endpoint&lt;/a&gt; handles this: give it a base URL, tell it which pages to find, and what to extract from each.&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;crawlSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;crawlInstruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extractInstruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxPages&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;fetch&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;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/crawl`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&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;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&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;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;crawlInstruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transformInstruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;extractInstruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;maxPages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useProxy&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="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;jobId&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;data&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;fetch&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;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/crawl/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jobId&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="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;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Crawl failed&lt;/span&gt;&lt;span class="dl"&gt;"&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="nf"&gt;log&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;progress&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crawling...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&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;// Example: crawl a competitor's blog for content strategy research&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&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;crawlSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://competitor.com/blog&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="s2"&gt;Find all blog post pages published in the last 6 months&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="s2"&gt;Extract the title, author, publish date, and a one-sentence summary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// posts → [{ url, title, data: { title, author, publish_date, summary } }, ...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 4: Geo-targeted scraping
&lt;/h3&gt;

&lt;p&gt;Some sites show different content based on the visitor's country: prices in local currency, region-specific inventory, geo-restricted offers. Use &lt;code&gt;proxyCountry&lt;/code&gt; to scrape from a specific location.&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;// Scrape a German Amazon page with a German IP&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.amazon.de/gp/bestsellers/electronics&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="s2"&gt;List the top 10 bestselling electronics with name and price in EUR&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;price_eur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&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="s2"&gt;number&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="s2"&gt;null&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;rank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&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="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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;proxyCountry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&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="c1"&gt;// Spidra supports 50+ country codes: us, gb, de, fr, jp, au, ca, br, in, ...&lt;/span&gt;
&lt;span class="c1"&gt;// Use "eu" for rotating EU proxies, "global" for worldwide rotation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 5: Authenticated scraping
&lt;/h3&gt;

&lt;p&gt;For pages behind a login: dashboards, account pages, paywalled content. Pass session cookies directly.&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;// Export cookies from your browser DevTools (Application → Cookies)&lt;/span&gt;
&lt;span class="c1"&gt;// or grab them with document.cookie from the console&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://app.example.com/dashboard/reports&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="s2"&gt;Extract monthly revenue, active users, and conversion rate for the last 3 months&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="s2"&gt;months&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;months&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;active_users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;conversion_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&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="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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;session=abc123; auth_token=xyz789; csrf=def456&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;h3&gt;
  
  
  Wiring it into an agent (full example)
&lt;/h3&gt;

&lt;p&gt;Here's a minimal but complete research agent using the &lt;a href="https://ai-sdk.dev/docs/introduction" rel="noopener noreferrer"&gt;Vercel AI SDK&lt;/a&gt; with &lt;code&gt;scrapeUrl&lt;/code&gt; as a &lt;a href="https://ai-sdk.dev/docs/reference/ai-sdk-core/tool" rel="noopener noreferrer"&gt;tool&lt;/a&gt;. The SDK handles the agentic loop: the model decides when to call the tool, the tool fetches live data, and the model reasons over the result.&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;generateText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tool&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="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;anthropic&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="s2"&gt;@ai-sdk/anthropic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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="s2"&gt;zod&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;result&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;generateText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;claude-opus-4-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;maxSteps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;scrapeUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetch and extract structured data from a URL. Use this when you need current information from a website.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&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;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The URL to scrape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What to extract from the page, in plain English&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;execute&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;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&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;data&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;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&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;stringify&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="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What are the top 3 trending repositories on GitHub today, and what do they do?&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;maxSteps&lt;/code&gt; lets the model make multiple tool calls in sequence if it needs to follow links, cross-reference sources, or refine its query. The scraping layer handles everything else. The model just decides what to fetch and what to ask for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical agent use cases
&lt;/h2&gt;

&lt;p&gt;To make this concrete, here are a few agent patterns that become viable with web access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Competitive intelligence agent:&lt;/strong&gt; Crawls competitor sites weekly, diffs pricing and feature changes, surfaces meaningful deltas to a Slack channel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead enrichment agent:&lt;/strong&gt; Given a list of company names, scrapes their websites, LinkedIn pages, and job boards to build structured profiles: company size, tech stack, recent hires, open roles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Research agent:&lt;/strong&gt; Given a topic, searches the web, scrapes the top results, synthesizes findings into a structured report with citations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Price monitoring agent:&lt;/strong&gt; Tracks SKUs across multiple retailers, alerts when prices drop below a threshold or when a product goes out of stock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;News digest agent:&lt;/strong&gt; Crawls a configured list of sources each morning, extracts headlines and summaries, sends a curated briefing tailored to the user's interests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these follows the same fundamental pattern: the agent knows what it wants, the scraping layer fetches and structures the data, and the agent reasons over clean output rather than raw HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Web access expands the category of problems an AI agent can tackle. A scraping tool lets it monitor competitor pages, research live topics, track prices, and respond to things happening right now. Without it, your agent is limited to reasoning over whatever it already knows.&lt;/p&gt;

&lt;p&gt;The implementation is straightforward: a submit-and-poll pattern, a JSON schema for the output shape, and a proxy-enabled API to handle the infrastructure. The agent doesn't need to know how any of that works. It just needs a reliable tool call that returns structured data. That's the interface worth building toward.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Understanding JavaScript Deobfuscation in Web Scraping</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Sat, 19 Apr 2025 15:34:05 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/understanding-javascript-deobfuscation-in-web-scraping-afo</link>
      <guid>https://forem.com/asaoluelijah/understanding-javascript-deobfuscation-in-web-scraping-afo</guid>
      <description>&lt;p&gt;Obfuscation is the process of deliberately making information more complex and harder to understand. Deobfuscation, on the other hand, is the method of reversing obfuscation to reveal the original information.&lt;/p&gt;

&lt;p&gt;Since web browsers have to expose webpages' source code, developers usually use different obfuscation techniques to make their code harder to read. This, in turn, makes life harder for web scrapers trying to pull useful content from such web pages.&lt;/p&gt;

&lt;p&gt;In this article, you’ll learn about obfuscating and deobfuscating web pages and practical tips for scraping data from obfuscated content.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Web Pages are Obfuscated
&lt;/h2&gt;

&lt;p&gt;Common methods for obfuscating web pages include:&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS Obfuscation
&lt;/h3&gt;

&lt;p&gt;Modern front-end build tools like Webpack and CSS modules provide features to obfuscate class names and IDs in HTML. They achieve this by generating unique or hashed class names that are difficult to predict. For example, a simple CSS class-based styling might look like this before obfuscation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;After obfuscation with Webpack, the class might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;._3iJ7sK&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;Now, in the HTML, a button that previously used &lt;code&gt;class="button"&lt;/code&gt; might use &lt;code&gt;class="_3iJ7sK"&lt;/code&gt;, which limits scrapers that rely on known class names to locate elements.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript Obfuscation with btoa
&lt;/h3&gt;

&lt;p&gt;JavaScript also has a native &lt;code&gt;btoa()&lt;/code&gt; function that converts a string into a base64-encoded string. While it’s a simple form of obfuscation, it does make raw text less readable. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&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;encodedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalString&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encodedString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: "SGVsbG8sIFdvcmxkIQ=="&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This technique is mostly used in HTML attributes, where encoded data is stored directly. For example, instead of seeing plain text in a &lt;code&gt;data-*&lt;/code&gt; attribute, you might find something like &lt;code&gt;data-value="U29tZSBzZWNyZXQgdGV4dA=="&lt;/code&gt;. Here, btoa has been used to encode "Some secret text," which makes it less obvious to identify at a glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deobfuscation Techniques in Web Scraping
&lt;/h2&gt;

&lt;p&gt;There are multiple strategies for scraping obfuscated web pages. Some common methods I've found useful include:&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS Selectors with Substring Matching
&lt;/h3&gt;

&lt;p&gt;When CSS classes are obfuscated, matching the exact class name can be tricky, as they may look like random strings that change frequently. To handle this, you can use substring matching in your CSS selectors. This way, you can match any class name containing a specific pattern, even if the entire name isn’t consistent.&lt;/p&gt;

&lt;p&gt;For example, let’s say you’re scraping a site where the "buy" button has a class name that always includes the substring &lt;code&gt;_buyBtn_&lt;/code&gt;, but the full class name might look something like &lt;code&gt;_buyBtn_3iJ7sK&lt;/code&gt; or &lt;code&gt;_buyBtn_x9L2kT&lt;/code&gt;. Instead of trying to match the whole class name exactly, you can use:&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="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;*=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_buyBtn_&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 selector matches any class containing &lt;code&gt;_buyBtn_&lt;/code&gt;. You can implement it in your scraper, as shown in the Node.js and Cheerio example below.&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;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&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;cheerio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cheerio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Sample URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;axios&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;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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="c1"&gt;// Find the button using substring matching&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buyButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;[class*="_buyBtn_"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Output the text inside the matched button element&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buyButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&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;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error fetching the page:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, you can focus on a stable part of the class name (&lt;em&gt;buyBtn&lt;/em&gt;) and reliably locate the necessary elements, even with obfuscation.&lt;/p&gt;

&lt;h3&gt;
  
  
  XPath with Wildcards
&lt;/h3&gt;

&lt;p&gt;XPath is another way to locate elements in HTML, similar to CSS substring matching; however, XPath allows for more complex logic. You can search for elements based on attributes, match elements by text content, navigate the document structure, and much more.&lt;/p&gt;

&lt;p&gt;For example, if you’re targeting an element with an obfuscated class attribute, you can use a wildcard like this:&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;//div[contains(@class, '_3iJ7sK')]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This XPath expression matches any &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element where the class attribute includes &lt;code&gt;_3iJ7sK&lt;/code&gt;. You can then implement the expression in a puppeteer and Node.js scraper, as shown below.&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;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;puppeteer&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="k"&gt;async &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;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&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;page&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Sample URL&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://example.com&lt;/span&gt;&lt;span class="dl"&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Find a div element with a class containing "_3iJ7sK"&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;targetElement&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="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;//div[contains(@class, '_3iJ7sK')]&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;targetElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Extract and print the text content&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetElement&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Element not found&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;As mentioned earlier, XPath can also select elements based on any attribute, not just class:&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;// Searches for a button element with type='submit'&lt;/span&gt;
&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;//button[@type='submit']&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;Select elements based on their text content.&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;// Selects an &amp;lt;a&amp;gt; tag with the exact text 'Click here'&lt;/span&gt;
&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a[text()='Click here']&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;XPath’s advanced logic makes it useful for scraping complex HTML structures with a level of precision that CSS selectors don't provide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decoding Base64 with atob
&lt;/h3&gt;

&lt;p&gt;If you come across content encoded with &lt;code&gt;btoa()&lt;/code&gt;, you can easily decode it using the &lt;code&gt;atob()&lt;/code&gt; function, as shown below:&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;encodedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SGVsbG8sIFdvcmxkIQ==&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;decodedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encodedString&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs: "Hello, World!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this might not be useful for scraping selectors, it can help you better understand the targeted content’s markup structure, especially in data attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Obfuscation is becoming increasingly common in web development, creating challenges for web scrapers that rely on structured data. This tutorial explored how these obfuscation techniques are implemented and provided methods to help overcome them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@chris_s3tudios?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Chris Stein&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-close-up-of-a-sign-with-a-lot-of-dots-on-it-ZPKJ3dEA88c?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Integrate Ollama in Next.js</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Thu, 06 Feb 2025 12:03:38 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/how-to-integrate-ollama-in-nextjs-5aa7</link>
      <guid>https://forem.com/asaoluelijah/how-to-integrate-ollama-in-nextjs-5aa7</guid>
      <description>&lt;p&gt;There’s no ignoring how AI and and large language models (LLMs) have dominated conversations lately. Nearly every week, new models are released, and new integrations (e.g AI agents and operators) are developed. It’s crazy not to want to jump on this exciting train.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to integrate Ollama with Next.js to build LLM-powered applications. We’ll cover how to download and interact with open-source LLMs (such as Llama, DeepSeek, and Mistral), as well as how to send messages and process LLM responses in Next.js using ollama.js. Our final application will look like the image shown below.&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.amazonaws.com%2Fuploads%2Farticles%2Fuwo9wls4qsyrcssbciyy.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fuwo9wls4qsyrcssbciyy.jpg" alt="Screenshot of a chat session with Ollama via a Next.js app" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisite
&lt;/h3&gt;

&lt;p&gt;To follow along, you should have a basic understanding of &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Large_language_model" rel="noopener noreferrer"&gt;how LLMs work&lt;/a&gt; behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Ollama?
&lt;/h2&gt;

&lt;p&gt;Ollama is an open-source framework founded by Michael Chiang and Jeffrey Morgan to simplify LLM integration with other applications. Ollama itself is not an LLM; instead, it allows you to download LLMs, interact with them, and create custom models. It also provides pre-configured API endpoints with which you can integrate downloaded or customized LLMs into other applications.&lt;/p&gt;

&lt;p&gt;It’s also worth mentioning that Ollama should not be confused with Llama (without the "O"). Llama is an open-source LLM developed by Meta AI. In contrast, Ollama is an independent open-source tool that enables integration with various LLMs. With that clarified, let’s explore these integrations in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up ollama
&lt;/h2&gt;

&lt;p&gt;To get started, &lt;a href="https://ollama.com/download" rel="noopener noreferrer"&gt;download Ollama&lt;/a&gt; from its official website. If you’re using other Unix/Linux distro, you can also download it by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you’ve successfully downloaded and installed Ollama, run the following command to verify that it is now executable on your terminal/command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything went well, you should see the version number printed in your console. Next, let’s install and interact with our first model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull and run a model
&lt;/h3&gt;

&lt;p&gt;As mentioned previously, Ollama provides access to multiple open-source models, including DeepSeek, Llama, Mistral, Qwen, and Phi. You can also view the list of supported models &lt;a href="https://ollama.com/search" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&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.amazonaws.com%2Fuploads%2Farticles%2Feajkv6k85nvm44c4yc2k.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Feajkv6k85nvm44c4yc2k.jpg" alt="Popular LLM models list on Ollama website" width="800" height="1064"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the model list, Llama 3.2 (by Meta AI) presently stands out as a small-sized model with impressive benchmark stats. It is available in two variants: 1B parameters (1.3GB) and 3B parameters (2GB). For this tutorial, we’ll use the Llama 3.2 1B model, as its smaller size makes it more manageable. To proceed, download the model by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run llama3.2:1b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will pull the Llama 3.2 (1B parameters) model from Meta’s registry. Once the download is complete, the model will launch, and you can start chatting with it right away, as shown in the screenshot below.&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.amazonaws.com%2Fuploads%2Farticles%2Fo1atawe22uo2ov9wtqju.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fo1atawe22uo2ov9wtqju.jpg" alt="Screenshot of a chat with llama3.2 on the terminal" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to spend some time interacting with the LLM directly from your terminal. Once you're ready, let’s dive into bringing it into a Next.js application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interact with LLMs in Next.js with Ollama.js
&lt;/h2&gt;

&lt;p&gt;Ollama provides REST API endpoints that allow you to interact with downloaded models. Once the desktop app is running, it exposes an endpoint at &lt;code&gt;http://localhost:11434/api&lt;/code&gt;, where you can send custom HTTP requests to perform interactions.&lt;/p&gt;

&lt;p&gt;For example, to generate an answer to the question &lt;em&gt;"What is Exorcism?"&lt;/em&gt;, we can send a POST request to the &lt;code&gt;/api/generate&lt;/code&gt; endpoint, specifying our preferred model and question, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:11434/api/generate &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
"model": "llama3.2",
"prompt": "What is Exorcism?"
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should then see the response objects streamed to your command line or terminal in real-time:&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.amazonaws.com%2Fuploads%2Farticles%2Fztsdfq0drc2s3z2kjt80.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fztsdfq0drc2s3z2kjt80.jpg" alt="Llama3.2 streaming response to the terminal" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To simplify the process, the Ollama team created a JavaScript library (&lt;a href="https://github.com/ollama/ollama-js" rel="noopener noreferrer"&gt;ollama-js&lt;/a&gt;) that comes pre-configured with various methods for referencing these endpoints and performing different tasks. We’ll leverage this library in our application.&lt;/p&gt;

&lt;p&gt;To proceed, create a new Next.js app by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app next-ollama
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the installation process, select Tailwind CSS and the pages/ router to ensure consistency with this tutorial. All other configuration options can be customized to your preference.&lt;/p&gt;

&lt;p&gt;Once your new Next.js app is successfully created, navigate to the project directory and install ollama-js by running the following commands:&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;cd &lt;/span&gt;next-ollama
npm &lt;span class="nb"&gt;install &lt;/span&gt;ollama
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s create a simple chat interface to interact with the LLM we installed earlier. Open the default &lt;code&gt;pages/index.js&lt;/code&gt; file and replace its contents with the following code:&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;useState&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="s2"&gt;react&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;Index&lt;/span&gt; &lt;span class="o"&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="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;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;handleSubmit&lt;/span&gt; &lt;span class="o"&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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;userMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* ====
    ⚠️ Main logic to be added later
    ==== */&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-2xl mx-auto p-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white min-h-[400px] p-4 mb-4 rounded-xl border-2 border-gray-500 overflow-y-auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`mb-4 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
              &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&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="s2"&gt;text-right&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="s2"&gt;text-left&lt;/span&gt;&lt;span class="dl"&gt;"&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="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
              &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`inline-block p-3 rounded-2xl max-w-[80%] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
                &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&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="s2"&gt;bg-blue-600 text-white&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="s2"&gt;bg-gray-100 text-gray-800&lt;/span&gt;&lt;span class="dl"&gt;"&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="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inline-block p-3 rounded-2xl bg-gray-100 text-gray-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nx"&gt;Thinking&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex gap-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
          &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex-1 p-3 rounded-xl border-2 border-gray-500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Type your message...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
          &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-blue-600 text-white px-6 py-3 rounded-xl hover:bg-blue-700 transition-colors font-medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Send&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above creates a basic chat interface that allows us to send messages and receive responses. It also includes a &lt;code&gt;handleSubmit()&lt;/code&gt; function, which doesn’t do much at this point, but this is where we’ll add the logic to process our messages with Ollama.&lt;/p&gt;

&lt;p&gt;Start your application by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should then see a chat interface similar to the image below.&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.amazonaws.com%2Fuploads%2Farticles%2Fo56wcddk054s8as5ygw1.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fo56wcddk054s8as5ygw1.jpg" alt="A simple chat interface" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s create an API endpoint to send our message to Llama 3.2 via Ollama and process the response. To do this, create a new chat.js file inside the default &lt;code&gt;pages/api/&lt;/code&gt; directory and paste the following code into it.&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="nx"&gt;ollama&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ollama&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="k"&gt;default&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;handler&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;res&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Method not allowed&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="k"&gt;try&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;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;body&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;response&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;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llama3.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&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;res&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;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;});&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ollama API error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to get response from LLM&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we imported Ollama and created a Next.js API endpoint that accepts POST requests with a message in the request body. Next, we called Ollama’s &lt;code&gt;.chat()&lt;/code&gt; method, specifying the LLM model we installed earlier (llama3.2) and passing the received message as part of the request object.&lt;/p&gt;

&lt;p&gt;To complete our integration, let’s update the main chat interface to communicate with the newly created endpoint. Open the &lt;code&gt;pages/index.js&lt;/code&gt; file and replace the existing &lt;code&gt;handleSubmit()&lt;/code&gt; function with the code below.&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;handleSubmit&lt;/span&gt; &lt;span class="o"&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&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;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nf"&gt;setInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&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;response&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/chat&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&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="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&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="s2"&gt;application/json&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;body&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to get response&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;aiMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&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;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;aiMessage&lt;/span&gt;&lt;span class="p"&gt;]);&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sorry, I encountered an error while processing your request.&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="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;At this stage, your &lt;code&gt;pages/index.js&lt;/code&gt; file should match the one provided &lt;a href="https://github.com/AsaoluElijah/ollama-next-js/blob/main/pages/index.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Finally, start your app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to the URL displayed in your console (typically &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt;), and you should now be able to chat with the Llama 3.2 LLM directly from your Next.js app, as shown in the image below.&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.amazonaws.com%2Fuploads%2Farticles%2Fuwo9wls4qsyrcssbciyy.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fuwo9wls4qsyrcssbciyy.jpg" alt="Screenshot of a chat session with Ollama via a Next.js app" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we’re done! You can now start interacting with a locally downloaded version of Llama 3.2 directly from your Next.js application. You can also pull other open-source models and interact with them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this tutorial, we covered how to install and download open-source large language models (LLMs) with Ollama, as well as how to use the ollama-js library to integrate these LLMs into a Next.js application. You can find the complete code used in this tutorial in this &lt;a href="https://github.com/AsaoluElijah/ollama-next-js" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In an upcoming follow-up article, we’ll explore how to stream responses and display them in real-time instead of waiting for the final computed response. We’ll also cover how to make the LLM remember our previous conversations, along with other ollama-js methods and community integrations. In the meantime, enjoy chatting with your custom-built LLM friend!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>nextjs</category>
      <category>programming</category>
    </item>
    <item>
      <title>Captio: Video Subtitles in Different Languages</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Mon, 11 Apr 2022 23:41:00 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/captio-video-subtitles-in-different-languages-2g1k</link>
      <guid>https://forem.com/asaoluelijah/captio-video-subtitles-in-different-languages-2g1k</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;Language has always been a barrier, but now, with recent technologies, we can translate live text in real time.&lt;/p&gt;

&lt;p&gt;However, this does not apply to video; it is still quite difficult to do so. And I'm sure we've all been in a position where we've seen a video clip on the internet (usually with a lot of interaction) and couldn't get the gist of it because it wasn't in our native language. Captio solves this barrier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Captio is a powerful bot that will generate subtitle for video files in any preferred language. Available via the following medium:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Twitter Bot - Twitter is inarguably one of the most used social media platform in the world, and it does make sense that a technology like this one is available on there.&lt;br&gt;
Check out &lt;a href="https://twitter.com/generate_sub/with_replies"&gt;caption on Twitter&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CLI Application - Captio is also available as a CLI application, so that you are able to generate translated subtitles offline.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Accessibility&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code on GitHub
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AsaoluElijah"&gt;
        AsaoluElijah
      &lt;/a&gt; / &lt;a href="https://github.com/AsaoluElijah/generate-sub"&gt;
        generate-sub
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Captio: Video Subtitles in Different Languages&lt;/h1&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/84a91621bada21e56c919c9cd6a07df10f8c6964f93054fcd0d94600a4018822/68747470733a2f2f7265732e636c6f7564696e6172792e636f6d2f70726163746963616c6465762f696d6167652f66657463682f732d2d73747237654559792d2d2f635f696d616767615f7363616c652c665f6175746f2c666c5f70726f67726573736976652c685f3432302c715f6175746f2c775f313030302f68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f397a65656b76627968666c78726d666d30786d762e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/84a91621bada21e56c919c9cd6a07df10f8c6964f93054fcd0d94600a4018822/68747470733a2f2f7265732e636c6f7564696e6172792e636f6d2f70726163746963616c6465762f696d6167652f66657463682f732d2d73747237654559792d2d2f635f696d616767615f7363616c652c665f6175746f2c666c5f70726f67726573736976652c685f3432302c715f6175746f2c775f313030302f68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f397a65656b76627968666c78726d666d30786d762e706e67" alt=""&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
Twitter bot x Cli program to generate subtitles in different languages.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Read article on &lt;a href="https://dev.to/asaoluelijah/captio-video-subtitles-in-different-languages-2g1k" rel="nofollow"&gt;Dev.to&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/AsaoluElijah/generate-sub captio
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; captio
npm install&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
API Keys&lt;/h3&gt;
&lt;p&gt;Once the installation is completed, make sure to rename &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and replace all the Twitter API keys and the Deepgram API key with yours.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Learn how to retrieve your Twitter API keys &lt;a href="https://developer.twitter.com" rel="nofollow"&gt;here&lt;/a&gt;, and Deepgram's &lt;a href="https://developers.deepgram.com/" rel="nofollow"&gt;here&lt;/a&gt; too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;h3&gt;
Cli&lt;/h3&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm run start:cli video=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;path/to/video&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; language=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;spanish&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Replace spanish with preferred language.&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
Twitter Bot&lt;/h3&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm start:bot&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;p&gt;MIT&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AsaoluElijah/generate-sub"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;Behind the seen, Captio uses a lot of open source API to perform it's operation, the diagram below sums it up pretty much.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RGcoRg7U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ax3aig3lz5bsk11idmnj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RGcoRg7U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ax3aig3lz5bsk11idmnj.png" alt="How it works" width="880" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nevertheless, you can checkout the full information on how it works &lt;a href="https://github.com/AsaoluElijah/generate-sub"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;On twitter, to let captio generate translated subtitle for a video tweet, you'll only need to reply the tweet mentioning captio (@generate_sub) like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CoqMlG1T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6b8u76xmn607cwxec1ql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CoqMlG1T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6b8u76xmn607cwxec1ql.png" alt="Captio usage on twitter" width="880" height="1266"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hackwithdg</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Getting Started With Nuxt.js - The How &amp; Why</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Tue, 24 Nov 2020 22:03:12 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/getting-started-with-nuxt-js-the-how-why-1g65</link>
      <guid>https://forem.com/asaoluelijah/getting-started-with-nuxt-js-the-how-why-1g65</guid>
      <description>&lt;h1&gt;
  
  
  What is Nuxt.js
&lt;/h1&gt;

&lt;p&gt;Nuxt.js is an intuitive vue.js framework (yeah, a framework’s framework) for building faster and scalable - static, server-side rendered (SSR) &amp;amp; single page applications (SPA’s).&lt;br&gt;
Nuxt.js is lovable because its included with vue core plugins by default (vue-router, vuex, vue-head,...), so no extra effort in installing them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Features (why 🤷🏽):
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auto import component:&lt;/strong&gt; You do not have to...
&lt;/li&gt;
&lt;/ul&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="nx"&gt;componentName&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;componentFolder&lt;/span&gt;&lt;span class="err"&gt;’&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="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;componentName&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;...for each of your components. Nuxt.js does that for you already, all you need do is keep all of your components in a folder and you could start referencing them anywhere in your application without doing the extra import.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;P.S:&lt;/strong&gt; there’s an option to disable this feature, in a case where you’re not interested in using it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auto generate router:&lt;/strong&gt; Yeah, routers are also generated automagically. For every new page or page/:slug you create, the routers are immediately generated/updated (awesome right?).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Middleware support:&lt;/strong&gt; Nuxt.js makes authentication in a vue.js based application seamlessly easy. You get to easily create and specify which middleware belongs to what page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;More awesome features:&lt;/strong&gt; The why list is literally endless. There are more features that nuxt.js provide for each pages, for example asyncData - that lets you render data before your page is mounted into view. But these features won’t be covered in this article, another one maybe.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Installation (How 🚀):
&lt;/h2&gt;

&lt;p&gt;Nuxt.js can be installed by downloading the &lt;code&gt;nuxt&lt;/code&gt; package from npm via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;nuxt —- save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, with this installation process, you’ll need to go through an extra step of creating the nuxt configuration file plus the folders required for your application (which is quite exhausting, IMO).&lt;/p&gt;

&lt;p&gt;Another option is using - &lt;code&gt;create-nuxt-app&lt;/code&gt; : an npx package created by the nuxt community.&lt;br&gt;
With this installation option, you will be prompted to select your type of application (SPA, SSA or static), select a front-end framework (bootstrap, vuetify or tailwind css) plus your preferred test and linting tool. And the nuxt configuration file will be generated automatically for you along with a sample nuxt.js application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Lets go ahead and create a basic  Nuxt.js application. Open your terminal/command line CD to your project folder and...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-nuxt-app sample-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Select rendering mode: Here you select the type of application you are building. &lt;strong&gt;Universal&lt;/strong&gt; - support for server side rendered applications. And &lt;strong&gt;Single page application&lt;/strong&gt; - For static/JAMStack based application.&lt;/li&gt;
&lt;li&gt;Deployment target - Here you specify how your application will be deployed. Static for Jamstack based hosting (like Netlify, github pages) and Server for Node.js based hosting (like Heroku and AWS).
The other required information are quite descriptive, like selecting programming language of choice (JavaScript/typescript), front-end framework and other related stuffs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After completing the above installation process, lets go ahead and open the project in your text-editor. I use vscode, so -&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;cd &lt;/span&gt;sample-project
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Directory structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;.nuxt/&lt;/strong&gt; - This folder is automatically generated and regenerated any time you start/build your projects - this is where routers, middleware and other related configs are created. we shouldn’t worry so much about this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;assets/&lt;/strong&gt; - This is where you keep your un-compiled assets including images, CSS, sass and fonts files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;components/&lt;/strong&gt; - This is where you keep your components files, of course.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pages/&lt;/strong&gt; - This folder contains your application views and routes, Nuxt.js reads all the &lt;code&gt;.vue&lt;/code&gt; files inside this directory and automagically creates the router configuration for you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;static/&lt;/strong&gt; - Here you keep static files that likely won't be changed. Unlike the assets dir, these files will be accessible through your project root URL. For example: &lt;code&gt;/static/robots.txt&lt;/code&gt; will be available at &lt;code&gt;http://localhost:3000/robots.txt&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;nuxt.config.js&lt;/strong&gt; - This file contains nuxt based configuration settings, here we can easily configure the default head (title, meta-tags) for each pages, add a global css file, configure build option, and many more.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Running/Building
&lt;/h3&gt;

&lt;p&gt;To run our app locally, all we need do is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our app should be served at &lt;code&gt;http://localhost:3030&lt;/code&gt; (or some other port, if :3030 is unavailable).&lt;/p&gt;

&lt;p&gt;If you’re building a static site, the distribution files can be generated by running..&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build is completed, a new &lt;strong&gt;dist/&lt;/strong&gt; folder will be created in your root directory. The content of this folder is what you host on your preferred platform - Netlify, GitHub pages, e.t.c.&lt;/p&gt;

&lt;p&gt;And if you are building a server side rendered application (SSR), &lt;a href="https://dev.to/fayaz/what-is-nuxtjs-ssr-universal-mode-and-how-to-host-it-for-free-3km4"&gt;here&lt;/a&gt; is an extensive article that should be helpful. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I guess I’ve been able to introduce you to what Nuxt.js is, why you should use it, plus how to get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to go from here?
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://nuxtjs.org/"&gt;Nuxt.js documentation&lt;/a&gt; is quite extensive and pretty straightforward. It’s included with everything you need to know about Nuxt.js. &lt;/p&gt;

&lt;p&gt;Fell free to also reach out to me on &lt;a href="http://twitter.com/asaolu_elijah"&gt;Twitter&lt;/a&gt;. 🕺 I’m open to discussing literally anything tech related. &lt;/p&gt;

&lt;p&gt;Thanks for reading. 👏&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>codenewbie</category>
      <category>nuxt</category>
    </item>
    <item>
      <title>How I Made My Personal Website 10x Faster ⚡</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Fri, 28 Aug 2020 15:12:15 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/how-i-made-my-personal-website-10x-faster-3p6k</link>
      <guid>https://forem.com/asaoluelijah/how-i-made-my-personal-website-10x-faster-3p6k</guid>
      <description>&lt;p&gt;I'd recently recreated my personal website, and the page load time reduced to &amp;lt; 1.6s 😮.&lt;br&gt;
You don't believe it? Check it out &lt;a href="https://asaolu.netlify.app" rel="noopener noreferrer"&gt;here&lt;/a&gt; to clear your doubts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While my personal website is built with Nuxtjs (Vue.js), all of the tips I'll be sharing could be easily implemented in whatsoever technology/framework you use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Light house Report 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAsaoluElijah%2Fportfolio%2Fmaster%2Flight-house-report.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAsaoluElijah%2Fportfolio%2Fmaster%2Flight-house-report.png" alt="Light house Report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without much Ado, let's dive into the tips.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Lazy load image:
&lt;/h3&gt;

&lt;p&gt;Lazy loading image in it's simplest term means waiting for your website contents to appear before displaying images asynchronously. Although you should show a placeholder - like a gray box - notifying the user that an image will be loaded here.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why lazy load images?
&lt;/h4&gt;

&lt;p&gt;Images could weigh alot most time, and this can have a negative impact on the time visitors have to wait before they can access your website content.&lt;/p&gt;
&lt;h4&gt;
  
  
  How to lazy load image
&lt;/h4&gt;

&lt;p&gt;Most front-end frameworks (bootstrap, materialize, chakra ui) these days provide a component to easily lazy load images on your website, kindly &lt;strong&gt;consult their documentation&lt;/strong&gt; for more info; And if you're using just traditional HTML, CSS and JavaScript - this &lt;a href="https://www.sitepoint.com/five-techniques-lazy-load-images-website-performance/" rel="noopener noreferrer"&gt;article&lt;/a&gt; might be helpful&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Below is an example of lazy loading with BootstrapVue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt; 
     &lt;span class="nt"&gt;&amp;lt;b-img-lazy&lt;/span&gt; &lt;span class="na"&gt;v-bind=&lt;/span&gt;&lt;span class="s"&gt;"mainProps"&lt;/span&gt; &lt;span class="na"&gt;:src=&lt;/span&gt;&lt;span class="s"&gt;"getImageUrl(80)"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Image 1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/b-img-lazy&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&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="nf"&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;mainProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;center&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;fluidGrow&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;blank&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;blankColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#bbb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&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="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-5&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="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;getImageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mainProps&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`https://picsum.photos/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;width&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;height&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/?image=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;imageId&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Avoid unused component
&lt;/h3&gt;

&lt;p&gt;In the first version of my website, I was using &lt;a href="https://github.com/mazipan/vue-ionicons" rel="noopener noreferrer"&gt;vue-ionicons&lt;/a&gt; and I'd imported a whole icon set globally 🤦‍♂️.&lt;br&gt;
You could image how long a user will have to wait before hundreds of icon components (that I'm not really using in the website) are loaded. That wasn't funny really 😬&lt;/p&gt;

&lt;p&gt;If using an icon component for example, avoid declaring the whole icon set as a global component.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Import only the icons you'll be using&lt;/strong&gt; - unless your website will be using 90% of the icons, which is very unlikely.&lt;/p&gt;

&lt;h4&gt;
  
  
  ✔️
&lt;/h4&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="nx"&gt;IconName&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;vue-ionicons/dist/js/icon-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-icon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IconName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ✖️
&lt;/h4&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="nx"&gt;AllIosIcon&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;vue-ionicons/dist/ionicons-ios.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AllIosIcon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Delete useless code block
&lt;/h3&gt;

&lt;p&gt;90% Developers are guilty of this - We all have that useless code block (although its commented), but we wouldn't want to delete them thinking they might be an answer to our questions later on 😅&lt;br&gt;
One thing I do is create a &lt;code&gt;temp&lt;/code&gt; file where I keep such code. So as not to make my main files bulky&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra: Minify your CSS and JS files
&lt;/h3&gt;

&lt;p&gt;If your website is built the traditional way, with no front-end library. Minifying your assets could also help in making your web pages load really faster.&lt;br&gt;
There's this awesome VSCode extension I use - &lt;a href="https://marketplace.visualstudio.com/items?itemName=josee9988.minifyall" rel="noopener noreferrer"&gt;minifyAll&lt;/a&gt; - it helps you minify your files in one click. It's blazing fast and.... it's the best out there.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbbAhxJj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FbbAhxJj.gif" alt="minifyAll VSCode extension"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This tips are in my own opinion (IMO), if you have a conflicting view, a better approach or tips like this generally. Kindly drop them in the comment box, I really enjoy learning.&lt;/p&gt;

&lt;p&gt;And..., my portfolio source code is hosted publicly &lt;a href="https://github.com/AsaoluElijah/portfolio" rel="noopener noreferrer"&gt;here&lt;/a&gt; on GitHub. I'll appreciate your ⭐.&lt;/p&gt;

&lt;p&gt;You can always reach out to me on &lt;a href="https://twitter.com/asaolu_elijah" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, if there is anything I can help you with.&lt;/p&gt;

&lt;p&gt;Thanks for reading 🤝&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Vue.js For Absolute Begineers </title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Thu, 30 Jul 2020 15:51:35 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/vue-js-for-absolute-begineers-1jdb</link>
      <guid>https://forem.com/asaoluelijah/vue-js-for-absolute-begineers-1jdb</guid>
      <description>&lt;p&gt;I've got my hands on vue.js lately and most tutorials I'd seen out there are not so beginners friendly, so i'd decided to start this series to help #codeNewbies go from beginners to intermediate in Vue.js.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please Note ⚠️:&lt;/strong&gt; You should have a basic understanding of HTML, CSS and JavaScript before learning Vue.js. If you do not, &lt;a href="https://www.w3schools.com/"&gt;here&lt;/a&gt; are great resources to help you get started.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Vue.js is a pogressive JavaScript framework for building interactive user interface. Vue.js is considered as a goto framework by many developers because it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier to learn compared to other frameworks/libraries like react, angular,... &lt;/li&gt;
&lt;li&gt;Have an easily understandable structure.&lt;/li&gt;
&lt;li&gt;Better runtime performance ...&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What can i build with Vue.js ?
&lt;/h3&gt;

&lt;p&gt;Below are some stuffs you can build with vue.js&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Page Applications (SPA)&lt;/li&gt;
&lt;li&gt;Multi Page Applications&lt;/li&gt;
&lt;li&gt;Native Android and iOS application - With Vue native&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Open your favourite text editor, create a new &lt;code&gt;index.html&lt;/code&gt; file and copy the basic html code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Vue.js Tutorial&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And, lets include the vue.js library source file in our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;[+...]
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, lets go ahead and create a new vue instance using the &lt;code&gt;new&lt;/code&gt; keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
[+...]
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;myMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome to my vue app.&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  So what have we done?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;new Vue(..&lt;/code&gt; keyword is to create a new instance from the Vue class. And this requires &lt;strong&gt;one important&lt;/strong&gt; parameter which is the &lt;code&gt;el&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;el&lt;/code&gt; is to specify where we want to wrap our vue application, and in this case it's our &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with the attribute id = wrapper&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Recall:&lt;/strong&gt; In &lt;a href="https://www.w3schools.com/js/js_htmldom.asp"&gt;DOM manipulation&lt;/a&gt; that &lt;code&gt;#&lt;/code&gt; (hash) is to id, while &lt;code&gt;.&lt;/code&gt; (fullstop) is to class. So that's why our &lt;code&gt;el&lt;/code&gt; value is #wrapper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Data
&lt;/h3&gt;

&lt;p&gt;During our new vue initialization, we'd added a second parameter &lt;code&gt;data&lt;/code&gt; - This is basically where we are going to house all the local properties we will be using while rendering our application, which is 100% reactivate (more on this later).&lt;/p&gt;

&lt;p&gt;To access our property &lt;em&gt;myMessage&lt;/em&gt; for example, our &lt;code&gt;index.html&lt;/code&gt; file should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Vue.js Tutorial&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{myMessage}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;myMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Welcome to my vue app.&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You'll notice we wrapped our myMessage in a mustache &lt;code&gt;{{}}&lt;/code&gt; structure. Other ways we can display our local properties is using the &lt;code&gt;v-text&lt;/code&gt; and &lt;code&gt;v-html&lt;/code&gt; attribute.&lt;br&gt;
The difference between the v-text and v-html is that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;v-text will display the data as plain text, while&lt;/li&gt;
&lt;li&gt;v-html will output the real html.
&amp;gt; Run the pen below to see the difference in action.
&lt;iframe height="600" src="https://codepen.io/asaoluelijah/embed/abdgaNE?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article is just an introduction to what vue.js is, and how to get started. In coming articles, I'll be covering crucial topics under Vue.js including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binding data&lt;/li&gt;
&lt;li&gt;Methods&lt;/li&gt;
&lt;li&gt;Components&lt;/li&gt;
&lt;li&gt;Looping in Vue&lt;/li&gt;
&lt;li&gt;Conditional rendering (if &amp;amp; else)&lt;/li&gt;
&lt;li&gt;Vue CLI&lt;/li&gt;
&lt;li&gt;Nuxt.js maybe?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And... we will be learning all this by building real world applications 🎊&lt;/p&gt;

&lt;p&gt;Okay, why not follow me on &lt;a href="https://twitter.com/asaolu_elijah"&gt;twitter&lt;/a&gt; so you'll be notified first when I write a new article.&lt;/p&gt;

&lt;p&gt;Thanks for reading 👏&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>tutorial</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Text To Speech In 3 Lines Of JavaScript</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Tue, 19 May 2020 17:14:42 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/text-to-speech-in-3-lines-of-javascript-b8h</link>
      <guid>https://forem.com/asaoluelijah/text-to-speech-in-3-lines-of-javascript-b8h</guid>
      <description>&lt;p&gt;If you're curious about trying this out, that's the 3 lines of code below 👇&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;var&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you're not in a hurry, this article explains everything you need to know about converting text to speech (spoken words) on the web with JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In a previous article, we'd explored the Web Speech API and also how to convert &lt;a href="https://dev.to/asaoluelijah/speech-recognition-with-javascript-4lh6"&gt;Speech To Text&lt;/a&gt;&lt;br&gt;
Another amazing feature of the Web Speech API is to convert Text to Speech.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Text To Speech != Speech To Text 🧐&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Text To Speech is when we give the computer some &lt;em&gt;words&lt;/em&gt; and the computer will say this words out loud in some robotic/human voice. While&lt;/li&gt;
&lt;li&gt;Speech To Text is when we say some words to the computer, and what we'd just said will be converted to &lt;strong&gt;text&lt;/strong&gt; (I guess this is explanatory enough)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The first thing we'll need to do is check if our browser supports the speech synthesis API. And the code below does that:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;speechSynthesis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Speech Synthesis supported 🎉&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;// Speech Synthesis Not Supported 😣&lt;/span&gt;
  &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sorry, your browser doesn't support text to speech!&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;p&gt;Next step is to create a new speechSynthesis object, add required property and make our app talk 👇&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;var&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Good Morning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Explanation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Line 1: We created a variable &lt;code&gt;msg&lt;/code&gt;, and the value assigned to it is a new instance of the &lt;code&gt;speechSynthesis&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;Line 2: The &lt;code&gt;.text&lt;/code&gt; property is used to specify the text we want to convert to speech&lt;/li&gt;
&lt;li&gt;And finally, the code on the 3rd(last) line is what actually make our browser talks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Altering Default Output
&lt;/h2&gt;

&lt;p&gt;The speechSynthesis API gives room to also change alter the default output like changing the &lt;strong&gt;voice, volume, speech rate, language, pitch&lt;/strong&gt; and more:&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;var&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SpeechSynthesisUtterance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;voices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getVoices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;voice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;voices&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="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume&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="c1"&gt;// From 0 to 1&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&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="c1"&gt;// From 0.1 to 10&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pitch&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;// From 0 to 2&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Como estas Joel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Supported Voices
&lt;/h2&gt;

&lt;p&gt;The code below helps you retrieve the list of all supported voices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;speechSynthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getVoices&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;voice&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;voice&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="nx"&gt;voice&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="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;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Well, there's nothing to conclude here I guess 🙃&lt;br&gt;
But you could follow me on &lt;a href="https://twitter.com/asaolu_elijah"&gt;Twitter&lt;/a&gt;, I tweet and retweet interesting technical stuffs; you sure want to see em.&lt;/p&gt;

&lt;p&gt;Thanks for reading 👏&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>api</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Covid-19 Reports - Get Updates Even When Offline</title>
      <dc:creator>Asaolu Elijah 🧙‍♂️</dc:creator>
      <pubDate>Thu, 30 Apr 2020 15:30:44 +0000</pubDate>
      <link>https://forem.com/asaoluelijah/covid-19-reports-get-updates-even-when-offline-4oep</link>
      <guid>https://forem.com/asaoluelijah/covid-19-reports-get-updates-even-when-offline-4oep</guid>
      <description>&lt;p&gt;In most African/Asian countries, most citizens tends not to get updates about the global covid-19 pandemic. One of the reasons being the lack of steady internet connection.&lt;/p&gt;

&lt;p&gt;The reports in Nigeria for example are updated every night around 8:00pm GMT and when this happens, it's only published on the Nigeria Center For Disease Control (NCDC) social handles. So if you have no access to the internet during this time, you'll be in the dark 🧟.&lt;/p&gt;

&lt;p&gt;This was why we'd brainstormed to create a solution for solving this, and then we came up with &lt;strong&gt;Covid-19 Reports&lt;/strong&gt; 💡&lt;/p&gt;




&lt;h2&gt;
  
  
  What We built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Covid-19 Reports&lt;/strong&gt; helps you channel your super power of getting the latest information about the covid-19 pandemic even when you're offline.&lt;/p&gt;

&lt;p&gt;You'll only need to access the web app once and prompted to add your mobile number in order to get the updates. After this you'll get all the updates you need everyday (automatically) 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Also:
&lt;/h3&gt;

&lt;p&gt;Visiting the app automatically detect your location (country precisely) and you'll only get reports based on this side, this was implemented so as not to bore 😴 you with large statistical data.&lt;/p&gt;

&lt;p&gt;Another awesome feature is performing self test right on your mobile phone. Since the covid-19 symptoms are known, we'd decided to automate self test without even having to visit the hospital.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Other amazing features including &lt;strong&gt;dark mode support&lt;/strong&gt;🤹&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Category Submission:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Covid-19 Solutions&lt;/li&gt;
&lt;li&gt;SMS API Integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo Link
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://inventorsdev.github.io/covid-hack/"&gt;https://inventorsdev.github.io/covid-hack/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/inventorsdev/covid-hack/"&gt;https://github.com/inventorsdev/covid-hack/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How We built it
&lt;/h2&gt;

&lt;p&gt;Covid-19 Reports is a progressive web app built with&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML, CSS, JavaScript, Framework 7 [Front End]&lt;/li&gt;
&lt;li&gt;PHP and SQL [Back End]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And SMS solution was made possible with Twilio SMS Api&lt;/p&gt;

&lt;p&gt;Also, automation was done with cron job on a Linux web server&lt;/p&gt;

</description>
      <category>twiliohackathon</category>
      <category>javascript</category>
      <category>html</category>
      <category>css</category>
    </item>
  </channel>
</rss>
