Chrome extension for Gmail labeling throws syntax error when using Gmail API

I’m building a Chrome extension that should automatically apply a “priority” label to selected emails when users click a custom button. I’m using InboxSDK for the button interface and Gmail API for the actual labeling, but I keep getting a syntax error.

The error shows up as:

Uncaught SyntaxError: Unexpected token <

This happens in my main script file. Here’s my setup:

// manifest.json
{
  "name": "Email Labeler",
  "description": "Auto-label emails",
  "version": "1.0",
  "manifest_version": 2,
  "background": {
    "page": "/background/main.html"
  },
  "content_scripts": [{
    "matches": ["https://mail.google.com/*"],
    "js": ["/libs/inboxsdk.js", "/scripts/labeler.js"],
    "run_at": "document_end"
  }],
  "permissions": ["identity", "https://www.googleapis.com/*"],
  "oauth2": {
    "client_id": "your-client-id.apps.googleusercontent.com",
    "scopes": ["https://www.googleapis.com/auth/gmail.modify"]
  }
}

// main.html
<!DOCTYPE html>
<html>
<head>
  <title>Email Labeler</title>
  <script src="authentication.js"></script>
</head>
<body>
  <div id="auth-section">
    <button id="auth-btn" onclick="startAuth()">Connect Gmail</button>
  </div>
</body>
</html>

// authentication.js
var APP_ID = 'your-client-id.apps.googleusercontent.com';
var PERMISSIONS = ['https://www.googleapis.com/auth/gmail.modify'];

function startAuth() {
  gapi.auth.authorize({
    'client_id': APP_ID,
    'scope': PERMISSIONS,
    'immediate': false
  }, authCallback);
}

function authCallback(result) {
  if (result && !result.error) {
    loadGmailClient();
  }
}

function loadGmailClient() {
  gapi.client.load('gmail', 'v1', applyLabels);
}

// labeler.js
function applyLabels() {
  var apiRequest = gapi.client.gmail.users.labels.list({
    'userId': 'me'
  });
  
  apiRequest.execute(function(response) {
    function setupToolbar(inboxSDK) {
      inboxSDK.Toolbars.registerToolbarButtonForList({
        title: 'Priority Label',
        iconUrl: chrome.extension.getURL('/icons/label.png'),
        onClick: function() {
          var selectedThreads = inboxSDK.Lists.getSelectedThreadRowViews();
          selectedThreads.forEach(function(thread) {
            thread.addLabel('Priority');
          });
          alert('Emails labeled as Priority');
        }
      });
    }
    
    InboxSDK.load('1', 'sdk_key_here').then(setupToolbar);
  });
}

What could be causing this syntax error? Any help would be appreciated.

Had the same issue. My authentication.js wasn’t loading the Google API client library properly. That “Unexpected token <” error happens when you’re expecting JavaScript but getting HTML instead - means gapi isn’t available when your code runs. You need to include the Google API library in main.html before your authentication.js script. Add <script src="https://apis.google.com/js/api.js"></script> in your head section. Then wrap your gapi calls with if (typeof gapi !== 'undefined') to check the library loaded first. Chrome extension timing is weird, so add error handling around your API initialization - it’ll save you hours of debugging.

Your script loading order is messed up. You’re trying to call gapi.client.gmail.users.labels.list() in your content script, but the Google API client library isn’t loaded there. The gapi object only exists in your background page where you’ve got the auth script.

I ran into this exact same issue when I started with Chrome extensions and Gmail API. Here’s what fixed it: move all your API calls to the background script and use message passing between your content script and background. Your content script should just handle the InboxSDK stuff, then send messages to the background script for actual Gmail API operations.

Also, make sure you’re loading the Google API client library in your background page by adding the script tag for https://apis.google.com/js/api.js in your main.html file.

yeah, that syntax error usually means ur getting HTML instead of js - the gmail API probably isn’t loading properly. check if gapi loads before calling it, and add some console.logs to see what’s happening.