<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Srujana Maddula</title>
    <description>The latest articles on DEV Community by Srujana Maddula (@srujana_maddula_3b6ab05ff).</description>
    <link>https://dev.to/srujana_maddula_3b6ab05ff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3621183%2Fa9f7a33d-9acb-459c-8253-413e40505da7.jpg</url>
      <title>DEV Community: Srujana Maddula</title>
      <link>https://dev.to/srujana_maddula_3b6ab05ff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srujana_maddula_3b6ab05ff"/>
    <language>en</language>
    <item>
      <title>Introducing SerpApi's OpenCode Plugin</title>
      <dc:creator>Srujana Maddula</dc:creator>
      <pubDate>Tue, 06 Oct 2026 10:03:36 +0000</pubDate>
      <link>https://dev.to/serpapi/introducing-serpapis-opencode-plugin-4j25</link>
      <guid>https://dev.to/serpapi/introducing-serpapis-opencode-plugin-4j25</guid>
      <description>&lt;p&gt;OpenCode is an open-source, model-agnostic AI coding agent that runs locally on your machine. It can edit files, run terminal commands, and work across multiple repos at once. Because it's model-agnostic, a lot of developers pair it with local LLMs like Ollama or LM Studio, so their code and data never leave their machine.&lt;/p&gt;

&lt;p&gt;But OpenCode can't search the web for live data unless you give it access. You can do that with the &lt;a href="https://github.com/serpapi/opencode-serpapi" rel="noopener noreferrer"&gt;SerpApi OpenCode plugin&lt;/a&gt;. It gives OpenCode access to Google, YouTube, Amazon, Walmart, and dozens of other search engines through a single tool call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an OpenCode Plugin?
&lt;/h2&gt;

&lt;p&gt;Plugins and Skills sound similar, but they do different jobs. Skills automate boring workflows, tasks where you'd otherwise repeat the same instructions every time. Plugins give OpenCode a new capability it didn't have before, a new tool, feature, or integration with an outside service.&lt;/p&gt;

&lt;p&gt;SerpApi has released one such plugin, giving OpenCode real-time web search. It provides access to multiple SerpApi engines like Google, Bing, Yahoo, YouTube, and many others. It also ships with skills that guide OpenCode in selecting appropriate engine and parameters for each query.&lt;/p&gt;

&lt;p&gt;So when a task needs live web data, OpenCode reaches for the SerpApi plugin, runs the search, and returns the results. Say OpenCode needs to find a current public GitHub repository for a coding task. It searches for it with the SerpApi plugin instead of guessing from training memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use SerpApi Opencode Web Search Plugin?
&lt;/h2&gt;

&lt;p&gt;Without the plugin, giving OpenCode web access means building a separate API integration yourself: handling auth, setting parameters, and parsing responses.&lt;/p&gt;

&lt;p&gt;The SerpApi OpenCode plugin replaces all of that with one integration. Install it once, and OpenCode gets dedicated access to specific engines and search verticals instead of just generic web search.&lt;/p&gt;

&lt;p&gt;Here are some of the popular engines the plugin supports:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vertical&lt;/th&gt;
&lt;th&gt;Supported engines&lt;/th&gt;
&lt;th&gt;Use cases&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Web Search&lt;/td&gt;
&lt;td&gt;Google, Bing, DuckDuckGo, Yahoo, Yandex, Baidu, Naver&lt;/td&gt;
&lt;td&gt;Full-featured web search with knowledge graph, ads, and SERP extras&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Search&lt;/td&gt;
&lt;td&gt;Google AI Mode, Google AI Overview, Bing Copilot, Brave AI Mode&lt;/td&gt;
&lt;td&gt;AI search results, brand monitoring in AI results, and AI-generated summaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shopping&lt;/td&gt;
&lt;td&gt;Amazon, Walmart, eBay, Google Shopping, Home Depot&lt;/td&gt;
&lt;td&gt;Product search, listings, and pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local&lt;/td&gt;
&lt;td&gt;Google Maps&lt;/td&gt;
&lt;td&gt;Local business listings and place reviews&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News &amp;amp; Trends&lt;/td&gt;
&lt;td&gt;Google News, Google Trends&lt;/td&gt;
&lt;td&gt;Current news articles and search trend data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Media&lt;/td&gt;
&lt;td&gt;Google Images, Google Videos, Google Lens, YouTube&lt;/td&gt;
&lt;td&gt;Image search, video search, reverse image search, and video rankings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Travel&lt;/td&gt;
&lt;td&gt;Google Flights, Google Hotels, Google Travel Explore&lt;/td&gt;
&lt;td&gt;Flight deals, hotel reviews, and travel destination search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jobs, Finance &amp;amp; Apps&lt;/td&gt;
&lt;td&gt;Google Jobs, Google Finance, Google Play, Apple App Store&lt;/td&gt;
&lt;td&gt;Job search, stock tracking, finance data analysis, and app store data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO&lt;/td&gt;
&lt;td&gt;Google Autocomplete&lt;/td&gt;
&lt;td&gt;Keyword research&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each engine returns data shaped for the question you're asking. For instance, searching Amazon returns product listings and pricing in clean JSON. You also don't need to remember engine names or query formats. OpenCode picks the right engine and parameters based on the query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the OpenCode SerpApi Plugin
&lt;/h2&gt;

&lt;p&gt;The OpenCode SerpApi plugin is available as an &lt;a href="https://www.npmjs.com/package/opencode-serpapi" rel="noopener noreferrer"&gt;npm package&lt;/a&gt;, so setup is really just a config change plus an API key.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add the plugin to your config
&lt;/h3&gt;

&lt;p&gt;In your project root, open &lt;code&gt;opencode.json&lt;/code&gt; (or &lt;code&gt;opencode.jsonc&lt;/code&gt;). If neither file exists, create &lt;code&gt;opencode.json&lt;/code&gt;. Then add &lt;code&gt;opencode-serpapi&lt;/code&gt; to the plugin array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://opencode.ai/config.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"opencode-serpapi"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want it available across all your projects instead of just one? Add the same block to your global config at &lt;code&gt;~/.config/opencode/opencode.json&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;OpenCode installs it automatically from npm the next time you run opencode in that project; doesn’t require a separate &lt;code&gt;npm i&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Set your SerpApi API key
&lt;/h3&gt;

&lt;p&gt;Grab a key from your &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;SerpApi dashboard&lt;/a&gt; and export it as an environment variable:&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;export &lt;/span&gt;&lt;span class="nv"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"add_your_api_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Start OpenCode
&lt;/h3&gt;

&lt;p&gt;On startup, OpenCode caches the plugin and registers the &lt;code&gt;serpapi_search&lt;/code&gt; tool for your session.&lt;/p&gt;

&lt;p&gt;Ask OpenCode something that needs a live web search, e.g.:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Search Google for the latest news on the Fed rate decision"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It returns live search results, 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj9qloqwlskucazq5hqe8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj9qloqwlskucazq5hqe8.jpg" alt="OpenCode web search plugin" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OpenCode web search plugin&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How OpenCode uses SerpApi under the hood?
&lt;/h2&gt;

&lt;p&gt;The plugin has three parts, each with a clear job: a connection to SerpApi's MCP server, a native search tool as a backup, and a skill that tells OpenCode which search engine to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The MCP connection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When OpenCode starts, the plugin automatically registers &lt;a href="https://serpapi.com/blog/introducing-serpapis-mcp-server/" rel="noopener noreferrer"&gt;SerpApi's hosted MCP server&lt;/a&gt; as a remote MCP server. You don't need to add it to your config by hand.&lt;/p&gt;

&lt;p&gt;The plugin reads your &lt;code&gt;SERPAPI_API_KEY&lt;/code&gt; environment variable and sends it as an &lt;code&gt;Authorization: Bearer&lt;/code&gt; header with each request.&lt;/p&gt;

&lt;p&gt;The server then checks the engine and its parameters, and runs the search. When OpenCode doesn't need the full JSON, it sets the engine's &lt;code&gt;output&lt;/code&gt; parameter to Markdown, which &lt;a href="https://serpapi.com/markdown-output" rel="noopener noreferrer"&gt;uses about half the tokens for the same task&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The &lt;code&gt;serpapi_search&lt;/code&gt; fallback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the MCP server isn't available, OpenCode can still search. The plugin exposes a native &lt;code&gt;serpapi_search&lt;/code&gt; tool that calls SerpApi's &lt;code&gt;search.json&lt;/code&gt; endpoint directly, using the runtime's built-in &lt;code&gt;fetch&lt;/code&gt;. The tool takes a single &lt;code&gt;q&lt;/code&gt; argument and maps it to the field each engine expects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The &lt;code&gt;serpapi-web-search&lt;/code&gt; skill&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The connection gives OpenCode access to various engines. The skill tells it which one fits the task, using bundled routing guidance and engine reference files.&lt;/p&gt;

&lt;p&gt;Ask OpenCode to find standing desks under $300 on Walmart, and the skill points it to the Walmart engine and its parameters. Without it, OpenCode might run a generic Google search and get blog posts and ads instead of product listings.&lt;/p&gt;

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

&lt;p&gt;This SerpApi plugin makes web search a native capability for OpenCode. It's open source, and setup just takes a config change and an API key.&lt;/p&gt;

&lt;p&gt;Check out the&lt;a href="https://github.com/serpapi/opencode-serpapi" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; if you want to see how it's built, report an issue, or request a feature.&lt;/p&gt;

&lt;p&gt;We are continuing to expand SerpApi integrations to make sure AI can access live search data, whether that is through &lt;a href="https://github.com/serpapi/serpapi-mcp" rel="noopener noreferrer"&gt;MCP&lt;/a&gt;, &lt;a href="https://github.com/serpapi/serpapi-claude-plugin" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, and many other AI integrations. If you dont find a SerpApi integration for the tool you work in, contact us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>opensource</category>
      <category>tools</category>
    </item>
    <item>
      <title>How to Give Hermes Agent Real-Time Web Search Results</title>
      <dc:creator>Srujana Maddula</dc:creator>
      <pubDate>Sat, 26 Sep 2026 16:57:05 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-give-hermes-agent-real-time-web-search-results-317o</link>
      <guid>https://dev.to/serpapi/how-to-give-hermes-agent-real-time-web-search-results-317o</guid>
      <description>&lt;p&gt;Ask an AI agent about something that happened this morning, a stock price, a breaking headline, or a product launch. Without access to real-time data, it either admits it doesn't know or, worse, gives you a confident answer that is completely wrong.&lt;/p&gt;

&lt;p&gt;That's the problem with AI agents that can't access the live web: they only know what the model learned during training. Hermes Agent's built-in web tools solve this. They let Hermes access live web data and use it for research, real-time monitoring, and scheduled tasks.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk you through how to connect Hermes Agent to real-time web search, how its web tools work, and a few practical use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Hermes Agent?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/NousResearch/hermes-agent" rel="noopener noreferrer"&gt;Hermes Agent&lt;/a&gt; is an autonomous AI agent that isn't tied to any IDE. You can run it on your laptop for local tasks or host it on a virtual server so it keeps running around the clock.&lt;/p&gt;

&lt;p&gt;Hermes has a built-in learning loop. It creates and updates its own skills as it works through your requests. Say you ask it to build a Python chatbot. To do that, it might create files, edit code, run tests, and fix whatever breaks along the way. Hermes then turns what it learns from that process into a skill it can reuse later.&lt;/p&gt;

&lt;p&gt;A week later, when you ask it to add a feature or deploy the app as a Docker container, it won't make you re-explain your stack from scratch. It recalls the project context from its persistent memory and reuses the skill it built the first time around. Over time, this compounds, every session adds to what Hermes knows about your setup, preferences, and workflows, so its understanding keeps deepening with each conversation.&lt;/p&gt;

&lt;p&gt;Hermes Agent works anywhere. Connect it to Slack, Telegram, WhatsApp, or your terminal. You can start a conversation on Telegram, and pick it up later from your Mac. If you host it on an always-on server, you can chat over WhatsApp or trigger a workflow via Slack, even when your laptop is off.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do Hermes Agent web tools work?
&lt;/h2&gt;

&lt;p&gt;Hermes Agent has two web tools: &lt;code&gt;web_search&lt;/code&gt; and &lt;code&gt;web_extract&lt;/code&gt;. The &lt;code&gt;web_search&lt;/code&gt; tool searches the web and gives the search results to the agent, while &lt;code&gt;web_extract&lt;/code&gt; extracts the web page content and provides that context to Hermes Agent.&lt;/p&gt;

&lt;p&gt;Basically, Hermes Agent exposes these tools to the AI model. The model then decides when to call a tool, passes in a search query, gets the results back, and uses those results in the next steps of the task.&lt;/p&gt;

&lt;p&gt;For example, say you ask Hermes, “What are the latest AI trends?”. The model sees that &lt;code&gt;web_search&lt;/code&gt; tool is available, along with the arguments "query" and "limit".&lt;/p&gt;

&lt;p&gt;The "limit" parameter defines the maximum number of search results the tool returns in a single call. "query" is the search query (whether that's the original user's query or an agent-refined query) that gets passed to the search provider.&lt;/p&gt;

&lt;p&gt;The model then generates a structured tool call, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web_search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest AI agent developments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes Agent then executes this tool call. Each result comes back with a title, URL, description, and position in the ranking.&lt;/p&gt;

&lt;p&gt;For this to work, you need to configure Hermes Agent with a backend provider that performs the actual search and returns the results. SerpApi offers 250 free searches per month. So you can &lt;a href="https://serpapi.com/blog/introducing-serpapis-hermes-agent-plugin/" rel="noopener noreferrer"&gt;configure &lt;code&gt;web_search&lt;/code&gt; to use SerpApi&lt;/a&gt;, and whenever Hermes Agent makes that tool call, SerpApi searches the web and returns the results to the agent.&lt;/p&gt;

&lt;p&gt;Hermes Agent also ships with &lt;a href="https://hermes-agent.nousresearch.com/docs/user-guide/features/browser" rel="noopener noreferrer"&gt;browser tools&lt;/a&gt;. Suppose you need to fill in a form to get the content, click a button to go to the next page, or scroll to load more content. Hermes provides tools like &lt;code&gt;browser_navigate&lt;/code&gt;, &lt;code&gt;browser_snapshot&lt;/code&gt;, &lt;code&gt;browser_click&lt;/code&gt;, &lt;code&gt;browser_type&lt;/code&gt;, &lt;code&gt;browser_scroll&lt;/code&gt;, and &lt;code&gt;browser_vision&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;browser_navigate&lt;/code&gt; opens the specified URL and initializes the browser session. Then &lt;code&gt;browser_snapshot&lt;/code&gt; captures the interactive elements on the page and assigns them reference IDs, like &lt;code&gt;@e1&lt;/code&gt; and &lt;code&gt;@e2&lt;/code&gt;. Hermes can then use those IDs with tools like &lt;code&gt;browser_click&lt;/code&gt; or &lt;code&gt;browser_scroll&lt;/code&gt; to interact with the page. Like web tools, you need to configure these browser tools with the supported backend providers like Browserbase, Browser Use, or others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right web search provider for Hermes Agent
&lt;/h2&gt;

&lt;p&gt;You can configure the &lt;code&gt;web_search&lt;/code&gt; and &lt;code&gt;web_extract&lt;/code&gt; tools with any supported provider, and they don't have to be the same one. You could use one provider for search and another one for extraction. SerpApi, Firecrawl, Tavily, and Brave Search are some popular providers you can use with Hermes.&lt;/p&gt;

&lt;p&gt;The main difference between providers is where the results come from and how they're shaped for the agent. SerpApi returns live results from Google, the same ones a person would see in their browser, instead of results from a separate search index. The &lt;a href="https://serpapi.com/blog/introducing-serpapis-hermes-agent-plugin/" rel="noopener noreferrer"&gt;SerpApi plugin&lt;/a&gt; also goes beyond general web search. It adds dedicated tools that Hermes picks automatically based on your request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;web_search&lt;/code&gt; uses the &lt;a href="https://serpapi.com/google-light-api" rel="noopener noreferrer"&gt;Google Light API&lt;/a&gt; for general queries, chosen for its compact responses and low latency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serpapi_maps_search&lt;/code&gt; pulls &lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps&lt;/a&gt; results with addresses, ratings, and review counts for queries like "coffee shops near me."&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serpapi_news_search&lt;/code&gt; pulls &lt;a href="https://serpapi.com/google-news-light-api" rel="noopener noreferrer"&gt;Google News&lt;/a&gt; results with publishers and dates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serpapi_shopping_search&lt;/code&gt; pulls &lt;a href="https://serpapi.com/google-shopping-light-api" rel="noopener noreferrer"&gt;Google Shopping&lt;/a&gt; results with prices and merchants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool returns only the fields Hermes needs, rather than a full raw response, which keeps the agent's context window lean. All four run on a single API key.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Backend search provider&lt;/th&gt;
&lt;th&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;web_extract&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Free tier&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SerpApi&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;250 free searches/month&lt;/td&gt;
&lt;td&gt;Google Search, Maps, News, and Shopping results in Markdown format for AI applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firecrawl&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;500 credits/month&lt;/td&gt;
&lt;td&gt;Generic research&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brave Search&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;2,000 queries/month&lt;/td&gt;
&lt;td&gt;Lightweight generic search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tavily&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Keyless option&lt;/td&gt;
&lt;td&gt;Pre-chunked, ready-to-use data for AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exa&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Keyless free tier&lt;/td&gt;
&lt;td&gt;Semantic search to find relevant web pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Paid&lt;/td&gt;
&lt;td&gt;Pre-summarized answers instead of raw pages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Power your Hermes AI agent with real-time web search
&lt;/h2&gt;

&lt;p&gt;You should already have Hermes Agent installed before connecting it to web search. If you're on a Mac, install it with a simple curl 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://hermes-agent.nousresearch.com/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also available on Windows or virtual servers. Follow this &lt;a href="https://hermes-agent.nousresearch.com/docs/getting-started/installation" rel="noopener noreferrer"&gt;quick installation guide&lt;/a&gt; to install it in your preferred environment.&lt;/p&gt;

&lt;p&gt;Once Hermes Agent is active, connect it to the &lt;a href="https://github.com/serpapi/serpapi-hermes-plugin" rel="noopener noreferrer"&gt;open-source SerpApi plugin&lt;/a&gt; to give it real-time web search access.&lt;/p&gt;

&lt;p&gt;Just go to Hermes chat mode and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install and configure serpapi-hermes-plugin by following the instructions at:
https://github.com/serpapi/serpapi-hermes-plugin#ask-hermes-to-install-it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes Agent will install and configure the plugin for you. It then asks for your SerpApi API key. If you don't have one yet, sign up for a SerpApi account and &lt;a href="https://serpapi.com/dashboard" rel="noopener noreferrer"&gt;get your API key from the dashboard&lt;/a&gt;. Once you have it, paste it into the terminal.&lt;/p&gt;

&lt;p&gt;To see if it works, I asked, “What is the current NVIDIA stock price?” and it returned the price accurately for that day.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fivxqfl5i3l001tv44lxu.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fivxqfl5i3l001tv44lxu.png" alt="Hermes Agent real-time web search" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hermes Agent real-time web search&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s not just for one-off questions. You can also schedule recurring workflows using simple natural language prompts. For example, you can ask, “Give me news updates every morning,” and Hermes will create a cron job to run the workflow and deliver the updates to you every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hermes Agent use cases
&lt;/h2&gt;

&lt;p&gt;Hermes Agent &lt;a href="https://hermes-agent.nousresearch.com/docs/user-stories" rel="noopener noreferrer"&gt;handles everything&lt;/a&gt; from serious coding to creating bedtime stories for your kids. I've picked out a few use cases where Hermes excels.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI research agent
&lt;/h3&gt;

&lt;p&gt;Hermes Agent's web search and extraction tools let it search the web in real time, analyze the information, summarize content, and pull out key insights. The engine you point it at shapes the results. For a broad question, Hermes starts with &lt;a href="https://serpapi.com/google-light-api" rel="noopener noreferrer"&gt;SerpApi Google Search&lt;/a&gt; to find relevant pages. For academic topics, &lt;a href="https://serpapi.com/google-scholar-api" rel="noopener noreferrer"&gt;Google Scholar&lt;/a&gt; returns papers and citations. For anything that happened this week, &lt;a href="https://serpapi.com/google-news-light-api" rel="noopener noreferrer"&gt;Google News API&lt;/a&gt; surfaces recent coverage that general search results might bury.&lt;/p&gt;

&lt;p&gt;So you can give Hermes a research task, and it can work through the web, gather information, and bring back the findings without you having to guide it through every step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Competitor research
&lt;/h3&gt;

&lt;p&gt;Freeze a watchlist of competitors, their domains, and a list of what you want to track: new hires, product launches, pricing changes, or major announcements. Then ask Hermes, “Every Monday morning, monitor these competitors and save the updates in a Markdown file.” Hermes Agent creates a cron job that runs this workflow automatically every Monday.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cold outreach
&lt;/h3&gt;

&lt;p&gt;Ask Hermes to scrape the internet for doctors in Boston, find leads who don’t have a website, and return 10 qualified leads to pitch your web development service.&lt;/p&gt;

&lt;p&gt;Hermes spawns multiple parallel agents, scrapes &lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps results&lt;/a&gt;, filters for qualified leads, then searches for their websites in Google Search, and returns their profiles and customized pitch angles for each of them.&lt;/p&gt;

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

&lt;p&gt;SerpApi's Google Search, Maps, News, and Shopping APIs provide real-time data across web results, local places, breaking news, and product prices. Connect them through the SerpApi plugin, and Hermes pulls the live information it needs and provide that context to the LLM. Since &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; offers 250 free searches per month, set up the SerpApi plugin as your search provider and power Hermes Agent with real-time web access.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Scrape YouTube Channel Results Using a Simple API</title>
      <dc:creator>Srujana Maddula</dc:creator>
      <pubDate>Fri, 25 Sep 2026 16:50:24 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-scrape-youtube-channel-results-using-a-simple-api-4nnm</link>
      <guid>https://dev.to/serpapi/how-to-scrape-youtube-channel-results-using-a-simple-api-4nnm</guid>
      <description>&lt;p&gt;If you’re tracking YouTube channels for competitor research, content strategy, or creator partnerships, you probably want answers for: How often is a competitor uploading? Are shorter videos performing better? Is a creator’s subscriber count actually growing?&lt;/p&gt;

&lt;p&gt;The data is all there on YouTube. But tracking all of it manually for multiple channels isn’t practical. That’s where scraping YouTube channel data can make the process much easier.&lt;/p&gt;

&lt;p&gt;In this guide, I'll show how to use the &lt;a href="https://serpapi.com/youtube-channel-api" rel="noopener noreferrer"&gt;SerpApi YouTube Channel API&lt;/a&gt; to scrape channel data. We’ll also look at what data you can collect and where to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping YouTube channel data with an API call
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; Get an API key
&lt;/h3&gt;

&lt;p&gt;Sign up with SerpApi and &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;grab your API key&lt;/a&gt;. You get 250 free searches per month (no credit card required).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Send a GET request
&lt;/h3&gt;

&lt;p&gt;Send a &lt;code&gt;GET&lt;/code&gt; request to SerpApi with &lt;code&gt;engine&lt;/code&gt; parameter set to &lt;code&gt;youtube_channel&lt;/code&gt; and add the &lt;code&gt;channel_id&lt;/code&gt; of the YouTube channel you want to scrape.&lt;/p&gt;

&lt;p&gt;You have two options to get the &lt;code&gt;channel_id&lt;/code&gt;. You can use the channel handle, which is the value you see after the &lt;code&gt;@&lt;/code&gt; in the YouTube channel URL. To target the SerpApi channel, for example, use &lt;code&gt;serpapi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alternately, you can use the channel’s raw ID. These IDs start with &lt;code&gt;UC&lt;/code&gt;, and you can find them on the channel page like in the below image. For example, this one is &lt;code&gt;UCUgIHlYBOD3yA3yDIRhg_mg&lt;/code&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4cwxvqoq22a1y1k53l9t.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4cwxvqoq22a1y1k53l9t.jpeg" alt="YouTube Channel ID" width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;YouTube Channel ID&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you have the channel ID, you can make a simple GET request to retrieve the channel data as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://serpapi.com/search?engine=youtube_channel&amp;amp;channel_id=serpapi&amp;amp;api_key=YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response includes channel metadata in &lt;code&gt;channel_results&lt;/code&gt; and a &lt;code&gt;videos_results&lt;/code&gt; array containing the channel's videos. Here's what an abridged version of that response looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"search_metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6aa77d5d3047f3a1de527a65"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"channel_results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SerpApi, LLC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"handle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@serpapi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Access real-time results from Google and 100+ search engines with a simple API. No proxies, CAPTCHAs, or parsing required."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"external_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UCUgIHlYBOD3yA3yDIRhg_mg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/channel/UCUgIHlYBOD3yA3yDIRhg_mg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subscribers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2840&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"video_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;186&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"videos_results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Supercharge Your AI Agents with Live Google Search Results (in Markdown)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=beqoAVXz7iA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"video_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"beqoAVXz7iA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"views"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"23 views"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"published_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7 hours ago"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4:23"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"serpapi_pagination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"next_page_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4qmFsgLZCRIYVUNVZ0lIbFlCT0Qz..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?channel_id=serpapi&amp;amp;engine=youtube_channel&amp;amp;next_page_token=4qmFsgLZCRIYVUNVZ0lIbFlCT0Qz..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3. Explore API parameters
&lt;/h3&gt;

&lt;p&gt;You can also play around with different parameters in the &lt;a href="https://serpapi.com/playground?engine=youtube_channel" rel="noopener noreferrer"&gt;SerpApi Playground&lt;/a&gt; to see how the response changes, and build the request for your use case.&lt;/p&gt;

&lt;p&gt;If you need more videos than the first page returns, you’ll find a &lt;code&gt;page_token&lt;/code&gt; in the JSON response. Pass it to your next request and collect videos from the next page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What YouTube Channel Data can you extract using this API?
&lt;/h2&gt;

&lt;p&gt;If you send a request with default parameters, you’ll get the full JSON response with information about the channel and its videos as a list.&lt;/p&gt;

&lt;p&gt;If you want to see the Shorts, Podcasts, Posts, or other tabs data on the channel, you just need to tweak the tab parameter to &lt;code&gt;shorts&lt;/code&gt;, &lt;code&gt;streams&lt;/code&gt;, &lt;code&gt;podcasts&lt;/code&gt;, &lt;code&gt;playlists&lt;/code&gt;, or others to get the data in those tabs.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;YouTube tabs scraper&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The overview below shows what information you’ll get for each of these tab results.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What it contains&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;channel_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Channel title, description, subscriber count, joined date, country, total views, and other channel information.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;videos_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Video position, title, description, views, length, and other video information.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shorts_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short position, title, link, views, and thumbnail details.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;streams_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stream position, title, link, waiting users, scheduled time, length, published date, and views.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;podcasts_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Title, last updated information, episode count, and thumbnail details.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;playlists_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Playlist position, playlist ID, video count, link, and other playlist information.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;posts_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post ID, author, text, published date, votes, attached video information, and other post details.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The API also supports a &lt;code&gt;search_query&lt;/code&gt; parameter that let's you add the text that you would normally search for within a YouTube channel. It then returns the matching videos and playlists in the &lt;code&gt;search_results&lt;/code&gt; field of the JSON response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping YouTube Playlist Results
&lt;/h2&gt;

&lt;p&gt;Let’s look at some code examples to scrape YouTube channel data. We’ll tweak the &lt;code&gt;tab&lt;/code&gt; parameter to scrape playlist results from any YouTube channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Python
&lt;/h3&gt;



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

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SerpApi_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube_channel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serpapi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tab&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playlists&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;playlists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playlists_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;playlists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Position:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Playlist:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Last updated:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;last_updated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of videos:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example prints the playlist’s position on the channel, the playlist link, when it was last updated, and the number of videos in the playlist. You can also modify the code to save the results to an Excel file or CSV.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidqhfecht9bolywlb99a.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidqhfecht9bolywlb99a.jpeg" alt="Scrape YouTube playlist results in Python" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scrape YouTube playlist results in Python&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For YouTube search results instead of just channel results, check out our tutorial on &lt;a href="https://serpapi.com/blog/how-to-scrape-youtube-data-with-simple-api/" rel="noopener noreferrer"&gt;how to scrape YouTube data in Python&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Ruby
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'serpapi'&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SerpApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;api_key: &lt;/span&gt;&lt;span class="s2"&gt;"SerpApi_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;engine: &lt;/span&gt;&lt;span class="s2"&gt;"youtube_channel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;channel_id: &lt;/span&gt;&lt;span class="s2"&gt;"serpapi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;tab: &lt;/span&gt;&lt;span class="s2"&gt;"playlists"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;playlists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:playlists_results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="n"&gt;playlists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Position: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:position&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Playlist: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"URL: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:link&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Last updated: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:last_updated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Number of videos: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;playlist&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:video_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"---"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6zmjyxbt0gv185p69jk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6zmjyxbt0gv185p69jk.jpeg" alt="Scrape YouTube playlist results in Ruby" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scrape YouTube playlist results in Ruby&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What can you do with YouTube Channel Data?
&lt;/h2&gt;

&lt;p&gt;YouTube is the second most visited search engine and it has a goldmine of public data for analytics. On average, over &lt;a href="https://blog.youtube/press/" rel="noopener noreferrer"&gt;20 million videos&lt;/a&gt; get uploaded daily, with nearly 2.5 billion active users per month watching videos, subscribing to channels, and leaving their comments. You can use all this data to understand different channels or audience in your niche.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build competitor monitoring tools:&lt;/strong&gt; Schedule a regular data extraction workflow to monitor your competitors’ subscriber growth, views, and compare them against yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prepare data backed content strategy:&lt;/strong&gt; Analyse your competitors’ top-performing Shorts, videos, or playlists. Look at their upload frequency, video length, and the number of episodes in their top-performing playlists, then use those insights to shape your content plan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Research market trends:&lt;/strong&gt; You can combine data across top channels and analyse their YouTube stats to get broader market trends in your niche.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spend your collaboration budget wisely:&lt;/strong&gt; You can extract the subscriber count, growth metrics, posting frequency, and audience engagement of potential creators, compare them, and pick the right one to collaborate with.&lt;/p&gt;

&lt;p&gt;If you also need to scrape individual video details like the description, likes, and comments, here’s a full tutorial on the &lt;a href="https://serpapi.com/blog/scrape-youtube-videos-in-python/" rel="noopener noreferrer"&gt;YouTube Video API&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;YouTube is a valuable source of data for understanding a channel’s credibility, audience engagement, and video performance. In this blog, you saw how to use the YouTube Channel API to collect channel-level data with a simple API call.&lt;/p&gt;

&lt;p&gt;SerpApi also provides other YouTube APIs for different use cases. For example, the &lt;a href="https://serpapi.com/youtube-search-api" rel="noopener noreferrer"&gt;YouTube Search API&lt;/a&gt; to scrape search results, the &lt;a href="https://serpapi.com/youtube-video-api" rel="noopener noreferrer"&gt;YouTube Video API&lt;/a&gt; to extract video details, and the &lt;a href="https://serpapi.com/youtube-video-transcript" rel="noopener noreferrer"&gt;YouTube Video Transcript API&lt;/a&gt; to extract video transcripts.&lt;/p&gt;

</description>
      <category>api</category>
      <category>tutorial</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>A Beginner’s guide to Instructor: Get Structured Outputs From LLMs</title>
      <dc:creator>Srujana Maddula</dc:creator>
      <pubDate>Fri, 24 Apr 2026 13:31:11 +0000</pubDate>
      <link>https://dev.to/srujana_maddula_3b6ab05ff/a-beginners-guide-to-instructor-get-structured-outputs-from-llms-3lco</link>
      <guid>https://dev.to/srujana_maddula_3b6ab05ff/a-beginners-guide-to-instructor-get-structured-outputs-from-llms-3lco</guid>
      <description>&lt;p&gt;LLM responses are unstructured text. That works fine when a human is reading the output. But when you need to feed it into an API, store it in a database, or pass it to another agent, you need specific fields, typed values, and a consistent structure.&lt;/p&gt;

&lt;p&gt;Thinking about writing a JSON parser for this? The problem is the model returns unpredictable text. It might skip fields, add extra text, or change the structure across calls, and you can't build a parser for output you can't predict.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll know how to handle this using Instructor library. I'll also walk through a real-world use case so you can adapt it to your own projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Instructor and How Does it Work?
&lt;/h2&gt;

&lt;p&gt;Instructor is an open-source Python library for getting structured output from LLMs. It supports many providers (OpenAI, Anthropic, Gemini, Ollama, DeepSeek, etc.) and guides them to return responses in a format you define.&lt;/p&gt;

&lt;p&gt;Here's the basic flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You define your output format as a Pydantic model.
&lt;/li&gt;
&lt;li&gt;Instructor derives a schema from that model and includes it in the LLM request.&lt;/li&gt;
&lt;li&gt;The model generates a response guided by that schema.&lt;/li&gt;
&lt;li&gt;Instructor validates the response and maps it to your Pydantic model. &lt;/li&gt;
&lt;li&gt; If validation fails, it retries with the error fed back to the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Install and Setup Instructor
&lt;/h2&gt;

&lt;p&gt;Install Instructor using pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;instructor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs Instructor with the OpenAI client by default. If you're using a different provider, install the relevant extra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"instructor[anthropic]"&lt;/span&gt;    &lt;span class="c"&gt;# Anthropic&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"instructor[google-genai]"&lt;/span&gt;    &lt;span class="c"&gt;# Google/Gemini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, make sure you have these installed before you start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.9+
&lt;/li&gt;
&lt;li&gt;Your model provider's client (e.g. &lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;anthropic&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Python-dotenv&lt;/code&gt; (recommended to manage API keys)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get Structured Outputs with Instructor and Pydantic Models
&lt;/h2&gt;

&lt;p&gt;Say you're building a customer support ticket routing system. A user submits a query and you want to extract specific fields from it: the order ID, issue type, priority, and requested action, then pass them to your routing logic. That's the use case we'll build here.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Load your API key
&lt;/h3&gt;

&lt;p&gt;To call OpenAI models, you need an API key. Get it from the &lt;a href="https://platform.openai.com/home" rel="noopener noreferrer"&gt;OpenAI platform&lt;/a&gt; and store it in a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OPENAI_API_KEY=your_api_key_here&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you're using a different provider, store their API key here instead.&lt;/p&gt;

&lt;p&gt;Then load it in your Python script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;  
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Define a Pydantic Model
&lt;/h3&gt;

&lt;p&gt;Instructor needs to know your expected output structure. You define that using a Pydantic model, a Python class with typed fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;  
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
   &lt;span class="n"&gt;issue_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delivery_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;technical_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;others&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="n"&gt;requested_action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replacement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;others&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;code&gt;SupportTicket&lt;/code&gt; inherits from Pydantic's &lt;code&gt;BaseModel&lt;/code&gt;. &lt;code&gt;Literal&lt;/code&gt; restricts &lt;code&gt;issue_type&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt;, and &lt;code&gt;requested_action&lt;/code&gt; fields to a fixed set of values, so if the model returns something outside that list, validation fails. &lt;code&gt;Optional&lt;/code&gt; on &lt;code&gt;order_id&lt;/code&gt; means it can be a string or None since not every ticket will have order ID information.&lt;/p&gt;

&lt;p&gt;Pydantic converts these type hints into validation rules at runtime. If the LLM returns a field with the wrong type, Pydantic either coerces it to the right type or flags it as invalid, which triggers Instructor's retry mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Call the Model
&lt;/h3&gt;

&lt;p&gt;To call the model, first patch the OpenAI client with Instructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call &lt;code&gt;client.chat.completions.create()&lt;/code&gt; with one addition: &lt;code&gt;response_model=SupportTicket&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;messages&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;It says my account is disabled. Can you unlock it?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model generates a response, Instructor parses it into the &lt;code&gt;SupportTicket&lt;/code&gt; schema and returns a validated &lt;code&gt;SupportTicket&lt;/code&gt; instance. If parsing or validation fails, it feeds the error back to the model and retries.&lt;/p&gt;

&lt;p&gt;Here's the full code together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;instructor&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;issue_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delivery_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;technical_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_issue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;others&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;requested_action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replacement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;others&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_openai&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;It says my account is disabled. Can you unlock it?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&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%2F461c0w2nkymycpau3xfs.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%2F461c0w2nkymycpau3xfs.png" alt="LLM structured output" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model classified the query as a technical issue with high priority, set the requested action to support, and left &lt;code&gt;order_id&lt;/code&gt; empty since no order was mentioned. That's a usable object your routing logic can act on directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to Explore Next
&lt;/h3&gt;

&lt;p&gt;This tutorial covered the basics, but there's more to Instructor. A few things worth adding to your implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error handling:&lt;/strong&gt; API calls can fail for a number of reasons: network issues, invalid API keys, or hitting the token limit. Wrap your calls in &lt;code&gt;try/except&lt;/code&gt; blocks and handle each failure case with a clear error message so your app doesn't break silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry limits:&lt;/strong&gt; Set the &lt;code&gt;max_retries&lt;/code&gt; parameter to control how many times Instructor retries before giving up. Pick a reasonable number that gives the model enough attempts to handle vague queries without burning through tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System prompts:&lt;/strong&gt; A system prompt is how you tell the model who it is and what it's supposed to do. Without one, the model just sees the user message and the schema with no context. For simple queries that's fine, but for vague inputs like "&lt;em&gt;I need help&lt;/em&gt;" the model starts guessing. Adding something like "&lt;em&gt;You are a support ticket classifier. Extract structured information from the user's message.&lt;/em&gt;" tells the model exactly how to interpret the input and keeps classification consistent across different queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nested models:&lt;/strong&gt; Once you're comfortable with flat models, try nesting Pydantic models inside each other. For example, a &lt;code&gt;SupportTicket&lt;/code&gt; model can include a nested &lt;code&gt;CustomerDetails&lt;/code&gt; model and a list of &lt;code&gt;IssueMetadata&lt;/code&gt; entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more advanced topics, check out &lt;a href="https://realpython.com/pydantic-ai/" rel="noopener noreferrer"&gt;Pydantic AI to build type-safe agents&lt;/a&gt;. If you're focused on OpenAI specifically, learn how to &lt;a href="https://realpython.com/chatgpt-api-python/#step-3-get-structured-outputs-with-pydantic-models" rel="noopener noreferrer"&gt;integrate the ChatGPT API into your Python projects&lt;/a&gt; and work with structured data. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>llm</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
