Extract LinkedIn Campaign Reporting Data with Python: A Step-by-Step Guide Using LinkedIn API

Extract LinkedIn Campaign Reporting Data with Python: A Step-by-Step Guide Using LinkedIn API

How to get LinkedIn Campaign Analytics Data with Python: A Step-by-Step Tutorial

Hello and welcome! Thank you for visiting. Want to dive deeper into your LinkedIn campaign data? Let’s leverage Python to extract valuable insights directly through the LinkedIn Advertising API. In this step-by-step guide, you’ll learn to develop a Python script to extract reporting data from LinkedIn using API. Specifically, we’ll use the LinkedIn Advertising API to retrieve valuable campaign performance data (Reporting or Analytics data)  from your LinkedIn Campaign Manager Account. This data can be leveraged for marketing research, performance analysis, and competitive insights.

With the growing demand for social network integration in applications, extracting data from social channels has become increasingly important. To connect with your LinkedIn Campaign Manager Account, the application must go through an authentication process using OAuth, requiring credentials like Access Token, App ID, App Secret, and Account ID. If you already have these credentials, you’re all set to begin. If not, don’t worry — we’ll guide you through setting up a LinkedIn Developer account and generating the necessary credentials in just three simple steps.

Extract LinkedIn Campaign Reporting Data with Python: A Step-by-Step Guide Using LinkedIn API
Extract LinkedIn Campaign Reporting Data with Python: A Step-by-Step Guide Using LinkedIn API

If you’re looking to maximize the potential of LinkedIn API integration, I’m here to help. Whether you have questions, need guidance, or automated token generation solutions, or require tailored consulting services, don’t hesitate to reach out. Let’s discuss how I can assist you in achieving your goals in just no time. Here are the ways you can connect with me, and let’s start a conversation about your unique requirements.

Pulling LinkedIn Campaign Data with Python: Code Structure and Files

Python Code Structure for calling LinkedIn API:

The project consists of the following files:

  • ln_main.py
  • get_linkedin_data.py
  • .env

I’ve developed code that can generate tokens, and extract data at the campaign group, campaign, ads, and creative levels. It efficiently handles pagination, date constraints, and API rate limits, and retrieves a wide range of metrics. If you’d like to get access to the code, feel free to get in touch with me directly on WhatsApp at +91 7892353323. You can also connect with me through LinkedIn or the provided Contact Form.

I’ll be happy to share the script and guide you through the integration process to ensure a smooth setup with your account. This can save you at least 5+ hours of effort, and I can also customize the code to meet your specific requirements.

1. Securely Store Credentials

Store your access token, refresh token, expiry time, and other credentials securely. Ideally, use cloud-based storage solutions like AWS Secrets Manager. Alternatively, store them in a .env file, which is designed to hold environment variables for a project. This method is recommended for this guide. While JSON files can be efficient for credential management, they are less secure and more vulnerable to unauthorized access.

Let’s create a .env file to manage your LinkedIn API credentials.

CLIENT_ID = "<Replace with your API app client ID >"
CLIENT_SECRET = "<Replace with your API app client secret >"
ACCESS_TOKEN = "<Replace with your API app access token >"
ACCOUNT_ID = "<Replace this with LinkedIn ads account ID>"

You can also get the code to extract LinkedIn Marketing account details and campaign reports from my GitHub repo through GitHub Link.

2. Create a main.py Python file

The main.py file serves as the core of your LinkedIn campaign data extraction project, controlling the overall flow. This is the file you’ll execute to run the project. Naming it main.py ensures easy access and management.

#!/usr/local/bin/python3
# command to run this code $ python3 ./main.py -s 2024-06-25 -e 2024-06-25
import getopt
import sys
import datetime
import json
import os
from dotenv import load_dotenv
load_dotenv()

from get_linkedin_data import *


def readfile(argv):
    global s_date
    global e_date

    try:
        opts, args = getopt.getopt(argv,"s:e:")
    except getopt.GetoptError:
        usage()
    for opt, arg in opts:
        if opt == '-s':
            s_date = arg
        elif opt == '-e':
            e_date = arg
        else:
            print("Invalid Option in command line")


if __name__ == '__main__':
    try:
        timestamp = datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d : %H:%M')
        print("DATE : ",timestamp,"\n")
        print("\n Process start")
        readfile(sys.argv[1:])
        

        access_token = os.getenv("ACCESS_TOKEN")
        account_id = os.getenv("ACCOUNT_ID")

        #call the LinkedIn API query function (i.e get_linkedin_campaign_data)
        ln_campaign_df = get_campaigns_list(access_token,account_id)
        print("\n All Campaigns :\n",ln_campaign_df)

        if not ln_campaign_df.empty:
            #get campaign analytics data
            campaign_ids = ln_campaign_df["campaign_id"]
            campaign_analytics = get_campaign_analytics(access_token,campaign_ids,s_date,e_date)
            print("\n campaigns analytics :\n",campaign_analytics)
        else:
            campaign_analytics = pd.DataFrame()

        print("\n campaigns analytics :\n",campaign_analytics)

        print("\n Process End \n")
    except:
        print("\n Process Failed !! ", sys.exc_info())

3. Create a get_linkedin_data.py python file to retrieve LinkedIn Campaign data

This file handles the core task of extracting reporting and analytics data from LinkedIn Campaigns using the LinkedIn Advertising API. I’ll name it get_linkedin_data.py. Currently, the code retrieves only campaign-level data, but you can expand it to include campaign groups, ads, and creative data as well.

In the sample code below, I’m fetching a few key metrics from a LinkedIn campaign. You can easily modify it to include additional fields from the LinkedIn Metrics list for more comprehensive data.

#!/usr/bin/python3
import requests
import pandas as pd
import sys
import json
from datetime import datetime, timedelta
import datetime
import re
from urllib import parse

#Function for date validation
def date_validation(date_text):
    try:
        while date_text != datetime.datetime.strptime(date_text, '%Y-%m-%d').strftime('%Y-%m-%d'):
            date_text = input('Please Enter the date in YYYY-MM-DD format\t')
        else:
            return datetime.datetime.strptime(date_text,'%Y-%m-%d')
    except:
        raise Exception('linkedin_campaign_processing : year does not match format yyyy-mm-dd')



def get_campaigns_list(access_token,account):
    try:
        url = "https://api.linkedin.com/v2/adCampaignsV2?q=search&search.account.values[0]=urn:li:sponsoredAccount:"+account

        headers = {"Authorization": "Bearer "+access_token}
        #make the http call
        r = requests.get(url = url, headers = headers)
        
        #defining the dataframe
        campaign_data_df = pd.DataFrame(columns=["campaign_name","campaign_id","campaign_account",
                            "daily_budget","unit_cost","campaign_status","campaign_type"])


        if r.status_code != 200:
            print("\n !! function (get_linkedIn_campaigns_list) something went wrong !! ",r)
        else:
            response_dict = json.loads(r.text)
            
            if "elements" in response_dict:
                campaigns = response_dict["elements"]
                print("\n Total number of campain in account : ",len(campaigns))

                #loop over each campaigns in the account
                campaign_list = []
                for campaign in campaigns:
                    campaign_name = None
                    campaign_id = None
                    campaign_acct = None
                    campaign_obj = None
                    daily_budget = None
                    unit_cost = None
                    tmp_dict = {}

                    #for each campign check the status; ignor DRAFT campaign
                    if "status" in campaign and campaign["status"]!="DRAFT":
                        if "name" in campaign:
                            campaign_name = campaign["name"]
                        tmp_dict["campaign_name"] = campaign_name
                        
                        if "id" in campaign:
                            campaign_id = campaign["id"]
                        tmp_dict["campaign_id"] = campaign_id
                        
                        if "account" in campaign:
                            campaign_acct = campaign["account"]
                            campaign_acct = re.findall(r'\d+',campaign_acct)[0]
                        tmp_dict["campaign_account"] = campaign_acct
                        
                        if "dailyBudget" in campaign:
                            daily_budget = campaign["dailyBudget"]["amount"]
                        tmp_dict["daily_budget"] = daily_budget

                        if "unitCost" in campaign:
                            unit_cost = campaign["unitCost"]["amount"]
                        tmp_dict["unit_cost"] = unit_cost

                        campaign_status = campaign["status"]
                        tmp_dict["campaign_status"] = campaign_status

                        campaign_list.append(tmp_dict)
            else:
                print("\n key *elements* missing in JSON data from LinkedIn")
            
            campaign_data_df = pd.DataFrame.from_records(campaign_list)
            
            try:
                campaign_data_df["daily_budget"] = pd.to_numeric(campaign_data_df["daily_budget"])
                campaign_data_df["unit_cost"] = pd.to_numeric(campaign_data_df["unit_cost"])
            except:
                pass

            return campaign_data_df
    except:
        print("\n !! function get_campaigns_list failed !!",sys.exc_info())



def get_campaign_analytics(access_token,campaigns_ids,s_date,e_date):
    try:
        #calling date validation funtion for start_date format check
        startDate = date_validation(s_date)
        dt = startDate+timedelta(1)
        week_number = dt.isocalendar()[1]
        #calling date validation funtion for end_date format check
        endDate = date_validation(e_date)
        #defining the dataframe
        campaign_analytics_data = pd.DataFrame(columns=["campaign_id","start_date","end_date",
                                    "cost_in_usd","impressions","clicks"])

        fields = "costInUsd, impressions, clicks"

        campaign_list = []
        for cmp_id in campaigns_ids:
            #Building api query in form of url 
            dateRange_start = "dateRange.start.day="+str(startDate.day)+"&dateRange.start.month="+str(startDate.month)+"&dateRange.start.year="+str(startDate.year)
            dateRange_end = "dateRange.end.day="+str(endDate.day)+"&dateRange.end.month="+str(endDate.month)+"&dateRange.end.year="+str(endDate.year)
            
            url = f"https://api.linkedin.com/v2/adAnalyticsV2?q=analytics&pivot=CAMPAIGN&{dateRange_start}&{dateRange_end}&timeGranularity=ALL&campaigns[0]=urn:li:sponsoredCampaign:{str(cmp_id)}&fields={fields}"
            
            #defining header for authentication
            headers = {"Authorization": "Bearer "+access_token}
            
            #make the http call
            r = requests.get(url = url, headers = headers)

            if r.status_code != 200:
                print("\n !! function (get_LinkedIn_campaign) something went wrong !! ",r)
            else:
                response_dict = json.loads(r.text)
                if "elements" in response_dict:
                    campaigns = response_dict["elements"]
                    
                    for campaign in campaigns:
                        tmp_dict = {}
                        cmp_costInUsd = float(campaign["costInUsd"])
                        tmp_dict["cost_in_usd"] = round(cmp_costInUsd,2)

                        cmp_impressions = campaign["impressions"]
                        tmp_dict["impressions"] = cmp_impressions

                        cmp_clicks = campaign["clicks"]
                        tmp_dict["clicks"] = cmp_clicks
                        
                        tmp_dict["campaign_id"] = cmp_id
                    
                        tmp_dict["start_date"] = startDate
                        tmp_dict["end_date"] = endDate
                        

                        tmp_dict["week"] = week_number
                        tmp_dict["month"] = startDate.month
                        
                        campaign_list.append(tmp_dict)
                else:
                    print("\n !! key *elements* missing in JSON data from LinkedIn !!")
        
        campaign_analytics_data = pd.DataFrame.from_records(campaign_list) 
        campaign_analytics_data["start_date"] = startDate
        campaign_analytics_data["end_date"] = endDate

        return campaign_analytics_data
    except:
        print("\n !! function get_campaign_analytics failed !! ",sys.exc_info())


Congratulations! You have successfully developed Python code to extract LinkedIn campaign analytics data using LinkedIn Adversting API. You can also look at Python code to extract LinkedIn Profile data (i.e. LinkedIn Account Details).

Hope I was able to solve the problem. If you like this article and think it was easy to understand do share it with your friends and connection. Thank you! See you soon.

For any suggestions or doubts ~ Get In Touch

Checkout out my other API Integration and Coding Solution Guide