linkedin-developers / linkedin-api-python-client

Official Python client library for LinkedIn APIs
Other
173 stars 35 forks source link

Example of how to make a request to the `adAnalytics` endpoint #32

Open nbro10 opened 1 year ago

nbro10 commented 1 year ago

I was having trouble to use the.finder method to make a request to the adAnalytics endpoint, so I'll share with you an example of how to use it

from linkedin_api.clients.restli.client import RestliClient

restli_client = RestliClient()
access_token = "my-access-token"

query_params = {'accounts': ['urn:li:sponsoredAccount:my_account'],
 'dateRange': {'end': {'day': 31, 'month': 5, 'year': 2020},
               'start': {'day': 1, 'month': 5, 'year': 2020}},
 'fields': 'impressions,pivotValues,dateRange',
 'pivots': ['CREATIVE', 'CAMPAIGN'],
 'projection': '(*,elements*(*,pivotValues(*~sponsoredCreative(content(reference)),*~sponsoredCampaign(name))))',
 'timeGranularity': 'ALL'}

response = restli_client.get(
            resource_path="/adAnalytics",
            finder_name="statistics",
            access_token=access_token,
            path_keys=None,
            query_params=query_params,
            version_string="202209",
        )

This could be used to write a proper example in the examples folder. If I have some time I'll do it.

The problem I was having was that I didn't realise that I had to pass the values to the parameters in a specific format (e.g. list of accounts, or dictionary of dictionaries for the dateRange) because I was previously using the xrestli protocol 1.0.0, which requires a different syntax.

shimizust commented 1 year ago

@nbro10 Thanks, yeah this would be a good example.

One of the big sources of confusion for folks is formatting query parameters or path keys in either rest.li 1.0 or 2.0 formats. Both protocols have very different, non-standard ways for representing both arrays/objects/special characters.

With the client, you can just pass in arrays as lists, objects as dictionaries, and special characters as is, and it will encode properly. One issue is that the documentation sometimes doesn't simply represent complex query parameters/path keys as JSON objects, and instead shows an example call with some encoded values already. So you first need to figure out the query parameter schema before using the client.

nbro10 commented 1 year ago

@shimizust Thanks for this info.

In addition to the differences between the protocols, I think one issue that I faced while writing this example (and my actual code that needed to call adAnalytics) was to understand the type of the object that I should pass to the query_params.

Specifically, as you can see, for the fields, instead of passing a list, which is what I would expect to pass, I'm passing a string. So, in my code, I actually need to do this: fields=",".join(['impressions', 'pivotValues', 'dateRange']). I think that, if you pass a list to fields, they will be encoded incorrectly (but I'd need to check that again). I also just tried to pass e.g. field1, field2 (i.e. with a space) and this led to a 403, so this can also lead to errors

Maybe the library should accept a list for the fields. What do you think?

Similarly, although decorations are deprecated/removed for adAnalytics in the LinkedIn version 202306, maybe this library could also provide some abstractions that simplify the way we request additional data with decorations. This may require quite some time to implement. So, maybe not worth the effort at this point

shimizust commented 1 year ago

@nbro10 Good question--the "fields" and "projection" properties are actually special parameters that don't follow the normal Rest.li spec.

"fields" is a special query param defined as part of the Rest.li spec, and while the documentation implies that it uses the same Rest.li protocol 2.0.0 encoding as other params, it actually doesn't. So the actual query parameter value would be: "fields=impressions,pivotValues" instead of "fields=List(impressions,pivotValues)".

"projection" is a LinkedIn API-specific query parameter that allows you to decorate an entity with other related entities.

Both "fields" and "projection" can have a complex format, as you see for projection (e.g. (*,elements*(*,pivotValues(*~sponsoredCreative(content(reference)),*~sponsoredCampaign(name))))) if you are trying to select elements in an array or nested properties.

Most people just copy/paste whatever is in the documentation, so for simplicity the library skips encoding the provided values for "fields" and "projection". And as you said, projections are being deprecated, so probably not worth it to simplify this part.

shimizust commented 1 year ago

I was considering before making "fields" a special parameter, but didn't think the complication would be worth it. It only makes sense for certain Rest.li methods. And there's also cases of nested "fields" parameters ...

But I should add some documentation around the "fields" parameter in the readme, which I see is missing.

nbro10 commented 1 year ago

@shimizust I think that, if it's simple enough to implement this, this library should accept a list of strings for the fields parameter. It's a lot more intuitive to specify the fields as a list of strings than as a string because we also do this for all other values in the query parameters (except fields and decorations). I wouldn't do it for the decorations because they are deprecated or are or will be removed. I see this package as a way to abstract away all the unnecessary complications and this seems like an issue that this package could solve

shimizust commented 1 year ago

@nbro10 I think the problem is "fields" isn't just a list of strings. It has the ability to select nested values in an object or nested values in an array so the syntax can be more complex. Implementing a new DSL to represent the field projections, and then converting to the proper query string, wouldn't be trivial.

Using complex field projections is perhaps less common--most people are probably just providing a list of top-level fields they want. I would consider maybe checking if "fields" is a simple string array and then just converting to a comma-delimited string in that case. Otherwise provide a more helpful error message

rdaries29 commented 9 months ago

Hey, I have come across a similar problem. I am trying to query linkedin analytics data using the API. Firstly, thanks for the repo 🙏 It has been really helpful 💯

Struggling at the moment to retrieve results for any campaigns for my ad account using the code above as the starting baseline. I am receiving an empty set when running the query. I checked Linkedin Campaign manager to see that there are analytics for active campaigns at the moment. Any help would be greatful 🙏 I also checked the access token to ensure permissions were correct.

I have attached screenshots for clarity.

Screenshot 2024-02-02 at 16 34 25 Screenshot 2024-02-02 at 16 34 35 Screenshot 2024-02-02 at 16 35 07 Screenshot 2024-02-02 at 16 37 39
vinit12321 commented 3 months ago

Hey, I have come across a similar problem. I am trying to query linkedin analytics data using the API. Firstly, thanks for the repo 🙏 It has been really helpful 💯

Struggling at the moment to retrieve results for any campaigns for my ad account using the code above as the starting baseline. I am receiving an empty set when running the query. I checked Linkedin Campaign manager to see that there are analytics for active campaigns at the moment. Any help would be greatful 🙏 I also checked the access token to ensure permissions were correct.

I have attached screenshots for clarity.

Screenshot 2024-02-02 at 16 34 25 Screenshot 2024-02-02 at 16 34 35 Screenshot 2024-02-02 at 16 35 07 Screenshot 2024-02-02 at 16 37 39

@rdaries29 Were you able to get this data?