Integrations

Google Sheets Integration

Use Google Apps Script to run AEO scores directly from a spreadsheet. Ideal for content teams who manage page audits in Sheets and want AEO scores added automatically alongside their existing data.

API access required
The Google Sheets integration uses the AEO Tool REST API. API access is available on Enterprise plans. You'll need an API key from Settings → API Keys.

Spreadsheet setup

Set up your spreadsheet with the following columns:

ColumnContentNotes
AURLFull page URL or leave blank for keyword-only analysis
BKeywordTarget query. Recommended for best recommendations
COverall ScoreWritten by script
D–J7 dimension scoresWritten by script (AEO Readiness through CRO)
KStatusRunning... / Done / Error — written by script

Row 1 is used for headers — the script writes the header labels in columns C–K automatically. Your data starts from row 2.

Installing the Apps Script

  1. Open your Google Sheet.
  2. Click Extensions → Apps Script.
  3. Delete any existing code in the editor.
  4. Paste the script below into the editor.
  5. Replace YOUR_API_BASE with your AEO Tool API base URL (see API Reference for your endpoint).
  6. Click Save (Ctrl+S / Cmd+S).
  7. Reload your spreadsheet. You'll see an 'AEO Tool' menu appear in the toolbar.
  8. Click AEO Tool → Configure API Key and enter your API key.
  9. Click AEO Tool → Run AEO Scores to start the analysis.
javascript
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('AEO Tool')
    .addItem('Run AEO Scores', 'showSidebar')
    .addItem('Configure API Key', 'setApiKey')
    .addToUi();
}

function setApiKey() {
  const ui = SpreadsheetApp.getUi();
  const result = ui.prompt(
    'AEO Tool',
    'Enter your API key:',
    ui.ButtonSet.OK_CANCEL
  );
  if (result.getSelectedButton() == ui.Button.OK) {
    PropertiesService.getUserProperties()
      .setProperty('AEO_API_KEY', result.getResponseText());
    ui.alert('API key saved.');
  }
}

function runAeoScores() {
  const apiKey = PropertiesService.getUserProperties()
    .getProperty('AEO_API_KEY');
  if (!apiKey) {
    SpreadsheetApp.getUi().alert(
      'Please set your API key first via AEO Tool > Configure API Key'
    );
    return;
  }

  const sheet = SpreadsheetApp.getActiveSheet();
  const lastRow = sheet.getLastRow();

  // Write headers to row 1
  sheet.getRange(1, 3, 1, 9).setValues([[
    'Overall Score',
    'AEO Readiness',
    'Retrieval Cost',
    'HTML5 Semantics',
    'Accessibility',
    'E-E-A-T',
    'Content Patterns',
    'CRO',
    'Status'
  ]]);

  for (let row = 2; row <= lastRow; row++) {
    const url = sheet.getRange(row, 1).getValue();
    const keyword = sheet.getRange(row, 2).getValue();
    if (!url && !keyword) continue;

    // Show progress
    sheet.getRange(row, 11).setValue('Running...');
    SpreadsheetApp.flush();

    try {
      const response = UrlFetchApp.fetch(
        'https://YOUR_API_BASE/api/analysis/',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + apiKey
          },
          payload: JSON.stringify({
            url: url || undefined,
            keyword: keyword,
            demo_mode: false
          }),
          muteHttpExceptions: true
        }
      );

      const result = JSON.parse(response.getContentText());
      const s = result.scores || {};

      sheet.getRange(row, 3, 1, 9).setValues([[
        result.overall_score || 0,
        s.aeo_readiness      || 0,
        s.information_retrieval_cost || 0,
        s.html5_semantics    || 0,
        s.accessibility      || 0,
        s.eeat               || 0,
        s.content_patterns   || 0,
        s.cro                || 0,
        'Done'
      ]]);

    } catch(e) {
      sheet.getRange(row, 11).setValue('Error: ' + e.message);
    }

    // Respect rate limits
    Utilities.sleep(2000);
  }

  SpreadsheetApp.getUi().alert('AEO scoring complete!');
}
Rate limits
The script includes a 2-second sleep between requests (Utilities.sleep(2000)) to respect the API rate limit. Do not reduce this value. Enterprise plans support up to 30 requests per minute. For very large sheets (500+ rows), consider running the script in batches.

Troubleshooting

Status shows 'Error: 401'
Your API key is incorrect or expired. Generate a new key at Settings → API Keys.
Status shows 'Error: 429'
You've hit the rate limit. The 2-second sleep should prevent this, but if you have a very fast network the requests may cluster. Increase Utilities.sleep to 3000.
'AEO Tool' menu doesn't appear
Reload the spreadsheet. If the menu still doesn't appear, check the Apps Script editor for syntax errors.
Score columns are empty but status shows 'Done'
The API returned a response but scores are missing. Check the raw response by logging: Logger.log(response.getContentText()) in the catch block.