> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mavera.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Keyword Research → Generate Pipeline

> Discover keyword opportunities via Google Ads KeywordPlanIdeaService and feed them into Mavera Generate to produce SEO blog post drafts.

### Scenario

You need blog content that targets real search demand, not guesswork. You use Google Ads' `KeywordPlanIdeaService` to discover keyword opportunities with volume and competition data, then feed the top keywords into Mavera's Generate endpoint to produce full SEO blog post drafts. The result is a content pipeline where every article is backed by search data.

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A[KeywordPlanIdeaService] --> B[Top keywords by volume] --> C["POST /api/v1/generations"] --> D[SEO blog post drafts]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests
  from google.ads.googleads.client import GoogleAdsClient

  MV = os.environ["MAVERA_API_KEY"]
  CUSTOMER_ID = os.environ["GOOGLE_ADS_CUSTOMER_ID"]
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  client = GoogleAdsClient.load_from_env()
  kw_service = client.get_service("KeywordPlanIdeaService")

  request = client.get_type("GenerateKeywordIdeasRequest")
  request.customer_id = CUSTOMER_ID
  request.language = "languageConstants/1000"  # English
  request.geo_target_constants = ["geoTargetConstants/2840"]  # US
  request.keyword_plan_network = client.enums.KeywordPlanNetworkEnum.GOOGLE_SEARCH
  request.keyword_seed.keywords.extend([
      "marketing automation", "content marketing software", "AI marketing tools"
  ])

  ideas = kw_service.generate_keyword_ideas(request=request)

  keywords = []
  for idea in ideas:
      m = idea.keyword_idea_metrics
      if m.avg_monthly_searches and m.avg_monthly_searches > 100:
          keywords.append({
              "keyword": idea.text,
              "volume": m.avg_monthly_searches,
              "competition": idea.keyword_idea_metrics.competition.name,
              "low_bid": m.low_top_of_page_bid_micros / 1_000_000 if m.low_top_of_page_bid_micros else 0,
              "high_bid": m.high_top_of_page_bid_micros / 1_000_000 if m.high_top_of_page_bid_micros else 0,
          })

  keywords.sort(key=lambda k: k["volume"], reverse=True)
  top_kw = keywords[:15]

  print(f"Found {len(keywords)} keywords, generating content for top {len(top_kw)}")

  for kw in top_kw[:5]:
      gen = requests.post(f"{MB}/generations", headers=MH, json={
          "prompt": (
              f"Write an SEO-optimized blog post outline and 300-word introduction for the keyword: \"{kw['keyword']}\". "
              f"Monthly search volume: {kw['volume']}. Competition: {kw['competition']}. "
              f"Target audience: B2B marketing professionals. "
              f"Include: H1, meta description, 5+ H2 subheadings, introduction paragraph. "
              f"Naturally incorporate the primary keyword and 2-3 related long-tail variations."
          ),
      }).json()

      print(f"\n{'='*50}")
      print(f"Keyword: {kw['keyword']} | Vol: {kw['volume']} | Comp: {kw['competition']}")
      print(f"Bid range: ${kw['low_bid']:.2f}–${kw['high_bid']:.2f}")
      print(f"{'='*50}")
      print(gen.get("output", gen.get("content", ""))[:600])
  ```

  ```javascript JavaScript theme={"dark"}
  const DEV_TOKEN = process.env.GOOGLE_ADS_DEVELOPER_TOKEN;
  const ACCESS_TOKEN = process.env.GOOGLE_ADS_ACCESS_TOKEN;
  const CUSTOMER_ID = process.env.GOOGLE_ADS_CUSTOMER_ID;
  const MV = process.env.MAVERA_API_KEY;
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const kwRes = await fetch(
    `https://googleads.googleapis.com/v23/customers/${CUSTOMER_ID}:generateKeywordIdeas`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${ACCESS_TOKEN}`, "developer-token": DEV_TOKEN, "Content-Type": "application/json" },
      body: JSON.stringify({
        language: "languageConstants/1000",
        geoTargetConstants: ["geoTargetConstants/2840"],
        keywordPlanNetwork: "GOOGLE_SEARCH",
        keywordSeed: {
          keywords: ["marketing automation", "content marketing software", "AI marketing tools"],
        },
      }),
    }
  ).then((r) => r.json());

  const keywords = (kwRes.results || [])
    .filter((idea) => parseInt(idea.keywordIdeaMetrics?.avgMonthlySearches || "0") > 100)
    .map((idea) => ({
      keyword: idea.text,
      volume: parseInt(idea.keywordIdeaMetrics.avgMonthlySearches),
      competition: idea.keywordIdeaMetrics.competition,
      lowBid: parseInt(idea.keywordIdeaMetrics.lowTopOfPageBidMicros || "0") / 1_000_000,
      highBid: parseInt(idea.keywordIdeaMetrics.highTopOfPageBidMicros || "0") / 1_000_000,
    }))
    .sort((a, b) => b.volume - a.volume);

  console.log(`Found ${keywords.length} keywords, generating for top 5`);

  for (const kw of keywords.slice(0, 5)) {
    const gen = await fetch(`${MB}/generations`, {
      method: "POST", headers: MH,
      body: JSON.stringify({
        prompt: `Write an SEO-optimized blog post outline and 300-word introduction for "${kw.keyword}". ` +
          `Volume: ${kw.volume}. Competition: ${kw.competition}. Audience: B2B marketing. ` +
          `Include: H1, meta description, 5+ H2 subheadings, introduction.`,
      }),
    }).then((r) => r.json());

    console.log(`\n${"=".repeat(50)}`);
    console.log(`Keyword: ${kw.keyword} | Vol: ${kw.volume} | Comp: ${kw.competition}`);
    console.log(`Bid: $${kw.lowBid.toFixed(2)}–$${kw.highBid.toFixed(2)}`);
    console.log((gen.output || gen.content || "").slice(0, 600));
  }
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
Found 142 keywords, generating for top 5

==================================================
Keyword: marketing automation software | Vol: 14800 | Comp: HIGH
Bid: $8.50–$24.00
==================================================
# H1: Marketing Automation Software: The 2026 Buyer's Guide

Meta: Compare the top marketing automation platforms by features, pricing,
and fit. Data-driven guide for B2B teams.

## H2 Outline
1. What Marketing Automation Software Actually Does
2. 7 Features That Separate Good Platforms from Great Ones
3. Marketing Automation Pricing: What to Expect in 2026
4. How to Evaluate Platforms for Your Team Size
5. Implementation Timeline and Common Pitfalls
6. Our Testing Framework: How We Ranked 12 Platforms

## Introduction (300 words)
Marketing automation software promises to do more with less — but the
category has 200+ vendors, and choosing wrong costs 6 months of migration...
```

### Error Handling

<AccordionGroup>
  <Accordion title="KeywordPlanIdeaService requires a plan or seed">You must provide at least one of `keyword_seed`, `url_seed`, or `site_seed`. An empty request returns `INVALID_ARGUMENT`.</Accordion>
  <Accordion title="Low volume keywords">Keywords with fewer than 10 monthly searches return `null` metrics. The code filters for `> 100` to ensure statistical relevance.</Accordion>
  <Accordion title="Geo and language constants">Use `languageConstants/1000` for English, `geoTargetConstants/2840` for US. Find IDs via `GET /v23/geoTargetConstants:suggest`.</Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="All Google Ads jobs" icon="rectangle-history" href="/integrations/google-ads">
    View all 7 Google Ads integration jobs
  </Card>

  <Card title="Generate API" icon="wand-magic-sparkles" href="/api-reference/generations">
    Full reference for POST /api/v1/generations
  </Card>
</CardGroup>
