Engineering Cover

How to Build a Custom Audience with PDL

July 15, 2022

15 minutes

Before You Start

Goal: Build a Custom Audience list using Python and the PDL Company Enrichment & Person Search APIs.

Level: Advanced – You know how to make API calls in Python and parse the response.

What You'll Need:

Credit Usage: If you run the code as-is in this tutorial, it will use:

  • 25 Company Enrichment Credits

  • 50 Person Search Credits


In this tutorial, we will walk through how to use PDL’s Company Enrichment and Person Search APIs to build a Custom Audience of decision makers at Software as a Service (SaaS) companies based in New York City.

What is a Custom Audience?

In marketing campaigns, it can be helpful to create Custom Audiences - lists of people who share certain characteristics that mean they may be interested in your product. Custom Audiences are frequently used in social media marketing campaigns (ex: Facebook and Twitter), since they can send tailored material directly to the people most likely to buy your product or service.

Step 1: Enrich Company Data from Initial List

Let’s assume that we were given a CSV file of potential NYC-based tech companies to build our Custom Audience from. However, all we have to go off of is very basic information for each company.

Since our Custom Audience requirements are more specific than the information we were given, this is an excellent opportunity to use PDL's Company Enrichment API.

Let’s pull PDL’s records for each company using the following code:

def enrich_company(name: str, website: str, linkedin: str) -> dict: resp = requests.get( '', headers=headers, params={ 'name': name, 'website': website, 'profile': linkedin } ) if resp.status_code != 200: raise ValueError(f'Request to {resp.request.url} failed. ' f'Response: {resp.status_code} - {resp.text}') return resp.json()

Call the function like this:

# convert the CSV to a pandas DataFrame initial_df = pd.read_csv(initial_list, header=0) # call the Company Enrichment API for each row in the DataFrame # and save the responses as a new DataFrame enriched_df = initial_df.apply( lambda row: enrich_company( row['name'], row['website'], row['linkedin_url'] ), result_type='expand', axis=1 ) print(enriched_df.head()) print(f'Enriched Data Size: {enriched_df.shape}')

Once you run the code, you should see:

status ... likelihood 0 200 ... 10 1 200 ... 10 2 200 ... 10 3 200 ... 10 4 200 ... 10 [5 rows x 26 columns] Enriched Data Size: (25, 26)

Step 2: Filter Company List using Criteria

The Company Enrichment API response contains a lot of information about each company in a standardized format. For more information on all the data in the Company Enrichment API response, see Company Schema.

From our Scenario, we know companies in our Custom Audience should be:

  • Based in New York City

  • In the Software as a Service (SaaS) industry

Since our initial list already provided only NYC-based companies, we can skip filtering for that and just determine which companies work in SaaS. 

PDL's tags field is a great way to find a company’s major associations, so let’s use it.

def filter_for_tag(to_filter: pd.DataFrame, tags: [str]) -> pd.DataFrame: # create a mask (True/False) for if each row has any of the tags mask = to_filter['tags'].dropna().apply( lambda row: any([tag in row for tag in tags])) # apply mask to filter DataFrame return to_filter[mask]

Call the function on the enriched DataFrame:

saas_df = filter_for_tag(enriched_df, ['saas']) print(saas_df.head()) print(f'Found {len(saas_df.index)} companies with "saas" tag')

Now we've filtered our initial list down to three NYC SaaS companies.

status name ... affiliated_profiles likelihood 8 200 pipedrive ... [] 10 10 200 datadog ... ['openview-'] 10 22 200 invisionapp inc ... [] 10 [3 rows x 27 columns] Found 3 companies with "saas" tag

Step 3: Find Decision Makers at Each Company

Now that we have our list, we want to find decision makers at the companies to advertise to. In this tutorial we define “decision makers” as all employees whose job title level is Director, VP, Partner, Owner, or “CXO” (CEO, CFO, CTO, etc.).

Let’s use PDL’s Person Search API to search each company for all employees that match our criteria. Each employee should:

  • Work for one of our targeted companies

  • Be a decision maker

  • Have a known work email (so our marketing material can reach them)

The Person Search API supports queries written in SQL or Elasticsearch. PDL strongly recommends using Elasticsearch, since it is what our architecture is based on and supports more detailed queries.

For more information on writing queries using Elasticsearch, see

In Elasticsearch, the query for our custom audience looks like this:

search_query = { 'query': { 'bool': { 'must': [ # work for one of our targeted companies {'terms': {'job_company_linkedin_url': company_linkedins}}, # be a decision maker {'terms': {'job_title_levels': ['owner', 'director', 'cxo', 'vp', 'partner']}}, # have a known work email {'exists': {'field': 'work_email'}} ] } } }

We can send the request to the Person Search API like this:

⚠️ Warning: High API Credit Usage ⚠️

This code snippet finds 50 profiles, costing 50 Person Search credits. If your plan’s rate limit is less than that, you can change the size parameter in the request to limit the number of responses or contact to increase your limit.

def get_decision_makers(company_linkedins: [str]) -> pd.DataFrame: # get 50 matches resp = '', headers=headers, json={ 'query': search_query, 'size': 50, # number between 1-100 'dataset': 'resume' } ) if resp.status_code != 200: raise ValueError(f'Request to {resp.request.url} failed. ' f'Response: {resp.status_code} - {resp.text}') return pd.DataFrame(resp.json()['data'])

Call the function like this:

companies = saas_df['linkedin_url'].values.tolist() audience_df = get_decision_makers(companies) print(f'Audience Data Size: {audience_df.shape}') print(f'Found {len(audience_df.index)} people for Custom Audience')

Which gives us 50 PDL profiles of decision makers at our target companies as a pandas DataFrame:

Audience Data Size: (50, 73) Found 50 people for Custom Audience

We’ve found our Custom Audience!

Step 4: Export the Custom Audience List

Depending on the marketing tool we want to use, we will export our Custom Audience DataFrame according to the tool's requirements.

For example, Twitter's Custom Audiences Tool supports a CSV of emails that we can build by exporting the DataFrame like this:

audience_df['work_email'].to_csv(filename, header=None, index=False)

Similarly, if we wanted to use Facebook's Custom Audiences Tool, we can build a CSV according to their specs like so:

headers = ['email', 'phone', 'fn', 'ln'] fields = ['work_email', 'mobile_phone', 'first_name', 'last_name'] audience_df[fields].to_csv(filename, header=headers, index=False)

What We’ve Accomplished

In this tutorial, we took a basic list of potential target companies and used it to build a highly targeted Custom Audience that we can use for an advertising campaign.

We walked through how to:

  1. Run a starting list of companies through the PDL Company Enrichment API to get more information about them

  2. Filter the dataset to target just the companies tagged “SaaS”

  3. Use the PDL Person Search API to find decision makers working at each target company

  4. Turn the person matches into Custom Audience CSVs that can be uploaded to Twitter and Facebook

See the full code for this tutorial here:

For More Information:

Questions? Reach out to, we’ll be happy to help!

Noticed any issues with this tutorial? Let us know at!

Call to Action
Natalie Nygaard
Natalie Nygaard