Parse Serper responses with its own field names. organic[i].link is the URL, organic[i].snippet is the description text, organic[i].position is the rank. News results add source and date; the knowledge graph sits at knowledgeGraph with title/type/description/attributes. When you write a normalizer that handles multiple search providers, add a Serper branch: map link to url and snippet to content. Do not assume fields from another provider carry over.

Context: Official docs (serper.dev homepage sample response): documents the actual Serper response shape. Results live in organic[], each item with title, link, snippet, position, sitelinks, and date. Extra blocks include knowledgeGraph (title, type, description, attributes), peopleAlsoAsk (question, snippet, title, link), and relatedSearches (query). The gotcha is that field names differ from every other search provider: it is link not url, and snippet not content. Mapping code written for Tavily or Exa breaks on this.