If you’ve ever manually copied LinkedIn Ad Analytics into a spreadsheet, you know it’s one of the most soul-draining tasks in digital marketing. Sure, LinkedIn gives you the data, but getting it into a useful format involves endless clicks, scrolling through reports, exporting CSVs, and then trying to organize it all into something your team or clients can actually read.

It’s tedious, it’s time-consuming, and worst of all, it’s repetitive. Every week, every month, you’re stuck doing the same thing. But what if you could just… not? What if you could automate the whole process and have the data show up exactly where you want it—without even lifting a finger?

That’s where Python and Google Sheets API come in. I built a simple script that:

  • Fetches daily campaign performance data for the last 90 days straight from LinkedIn.

  • Dumps it directly into Google Sheets, so you can say goodbye to manual entry and focus on the actual analysis.

Let’s dive into how to set this up and save yourself a ton of time.

Step 1: Set Up the Google Sheets API

First things first, you need to get access to Google Sheets from your Python script. It sounds complex, but once it’s set up, it’s a breeze. Here’s how to do it:

  • Go to the Google Cloud Console and create a new project.

  • Enable the Google Sheets API and the Google Drive API.

  • Create credentials – for automation, I recommend using a Service Account.

  • Download the JSON credentials file. You’ll need this to authenticate your Python script.

Step 2: Install the Required Python Libraries

You’ll need to install gspread and google-auth to connect your Python script to Google Sheets. Fire up your terminal and install them using pip:

pip install gspread google-auth

This will take care of the API connection part.

Step 3: Write the Python Script

Now, let’s write the Python script that will:

  • Fetch your LinkedIn Ad Analytics data using LinkedIn’s API.

  • Dump the daily performance data for the last 90 days into your Google Sheet.

Here’s the code:

import requests
from datetime import datetime, timedelta
import gspread
from google.oauth2.service_account import Credentials

# Google Sheets setup
scope = [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/drive",
]
creds = Credentials.from_service_account_file("path_to_credentials.json", scopes=scope)
client = gspread.authorize(creds)

# Open your Google Sheet
spreadsheet = client.open("LinkedIn Analytics Data")  # change to your sheet name
sheet = spreadsheet.sheet1

# Clear the sheet before writing new data
sheet.clear()

# LinkedIn setup
ACCOUNT_ID = "YOUR_ACCOUNT_ID"  # numeric ID from Campaign Manager
ACCESS_TOKEN = "YOUR_LINKEDIN_ACCESS_TOKEN"
ACCOUNT_URN = f"urn%3Ali%3AsponsoredAccount%3A{ACCOUNT_ID}"

headers = {
    "Authorization": f"Bearer {ACCESS_TOKEN}",
    "LinkedIn-Version": "202604",
    "X-Restli-Protocol-Version": "2.0.0",
}

# Fetch campaign names so we can label each row
campaigns_url = f"https://api.linkedin.com/rest/adAccounts/{ACCOUNT_ID}/adCampaigns?q=search"
response = requests.get(campaigns_url, headers=headers)
campaign_id_to_name = {}

if response.status_code == 200:
    for campaign in response.json().get("elements", []):
        campaign_id = str(campaign.get("id"))
        campaign_id_to_name[campaign_id] = campaign.get("name", "Unknown Campaign")
else:
    print(f"Failed to fetch campaigns. Status: {response.status_code}, {response.text}")

# Fetch the last 90 days of daily campaign analytics
all_data = []
today = datetime.today()

for i in range(90):
    day = today - timedelta(days=i)
    date_str = day.strftime("%Y-%m-%d")

    analytics_url = (
        "https://api.linkedin.com/rest/adAnalytics?q=analytics"
        f"&dateRange.start.day={day.day}&dateRange.start.month={day.month}&dateRange.start.year={day.year}"
        f"&dateRange.end.day={day.day}&dateRange.end.month={day.month}&dateRange.end.year={day.year}"
        "&timeGranularity=DAILY&pivot=CAMPAIGN"
        f"&accounts=List({ACCOUNT_URN})"
        "&fields=clicks,costInLocalCurrency,impressions,pivotValues"
    )

    response = requests.get(analytics_url, headers=headers)

    if response.status_code == 200:
        for row in response.json().get("elements", []):
            clicks = row.get("clicks", 0)
            impressions = row.get("impressions", 0)

            # LinkedIn returns money fields as strings, not numbers
            try:
                cost = float(row.get("costInLocalCurrency") or 0)
            except (TypeError, ValueError):
                cost = 0.0

            campaign_id = row.get("pivotValues", [""])[0].split(":")[-1]
            campaign_name = campaign_id_to_name.get(campaign_id, "Unknown Campaign")

            all_data.append({
                "Date": date_str,
                "Campaign": campaign_name,
                "Clicks": clicks,
                "Impressions": impressions,
                "Cost": f"{cost:.2f}",
            })
    else:
        print(f"Failed to fetch analytics for {date_str}. Status: {response.status_code}, {response.text}")

# Write everything to Google Sheets
sheet.append_row(["Date", "Campaign", "Clicks", "Impressions", "Cost"])

for entry in all_data:
    sheet.append_row([entry["Date"], entry["Campaign"], entry["Clicks"], entry["Impressions"], entry["Cost"]])

print("Data successfully dumped into Google Sheets!")

Step 4: Run the Script

When you run the script, it will:

  • Authenticate with the Google Sheets API using the credentials file.

  • Fetch daily LinkedIn Ads performance data for the last 90 days.

  • Dump all this into a neatly formatted Google Sheet.

Once set up, you can schedule this script using cron or any other scheduling tool to run daily, weekly, or however frequently you need it.

Final Thoughts

Automating your LinkedIn Ads data export is a game changer, especially if you’re juggling multiple campaigns. It saves you time and lets you focus on analyzing performance instead of being bogged down by manual data handling. With this Python script, your LinkedIn data goes straight to Google Sheets, making your reporting process smoother than ever.

You’re welcome. 😉