Can't find a way to get number of clicks, using Selector Fields

247 views
Skip to first unread message

samuel...@gfrmedia.com

unread,
Mar 25, 2015, 6:18:27 PM3/25/15
to adwor...@googlegroups.com
Hi everyone. If someone can help me, I will really appreciate it.

I am trying to get some basic information from a Campaign under my test MCC account. I am using Selector Fields to do so. 

I can get the Campaign Id, the Campaign Name, and some other info... but I just cannot find a way to retrieve the number of click at the Campaign Level, nor the Ad Groups level.

Basically, I'm just trying to get all the information from this table:

I can get my Campaign Name also... I just don't find any selector which I could retrieve those clicks. 

Here is an example of what I'm doing in C#:

AdWordsUser user = new AdWordsUser();

            CampaignService campaignService = (CampaignService)user.GetService(AdWordsService.v201409.CampaignService);
            DataService dataService = (DataService)user.GetService(AdWordsService.v201409.DataService);
            AdGroupService adGroupService = (AdGroupService)user.GetService(AdWordsService.v201409.AdGroupService);

            Selector CampaignServiceSelector = new Selector();
            CampaignServiceSelector.fields = new string[] { "Name", "Id", "Status" };


            Selector DataServiceSelector = new Selector();
            DataServiceSelector.fields = new string[] {"LocalClicks", "LocalImpressions"};

            Selector adGroupServiceSelector = new Selector();
            adGroupServiceSelector.fields = new string[] { "Status", "Name" };


            var campaignInfo = campaignService.get(CampaignServiceSelector);
            var dataServiceInfo = dataService.getCriterionBidLandscape(DataServiceSelector);
            var adGroupServiceInfo = adGroupService.get(adGroupServiceSelector);

I'm just "playing" with the selectors, and I have a pretty good idea of how I will create the report that I want. I just don't find a selector to retrieve those clicks that I marked yellow at that picture. I tried to use DataService object, which have a method called "getAdGroupBidLandscape" that seems to have a selector that could work (LocalClicks) but when I use it, the code returns 0 entries.

I'm lost! What selector I should use to retrieve those clicks? 

Please help! Thank you :)

Thanet Knack Praneenararat (AdWords API Team)

unread,
Mar 26, 2015, 10:13:58 AM3/26/15
to adwor...@googlegroups.com
Hi Samuel,

Based on what you've described, it seems you may want to use reporting feature of the API.

To get number of clicks and impressions for each campaign, you can use Campaign Performance Report to obtain those relevant fields.

Please refer to this C# code example for more information. 
In the code, Criteria Performance Report is specified but you can adapt to use Campaign Performance Report quite easily.

Best,
Thanet, AdWords API Team

Samuel Otero

unread,
Mar 26, 2015, 11:04:09 AM3/26/15
to adwor...@googlegroups.com
Hello Thanet. I really appreciate your fast answer.

I'm also working with the reporting feature approach, and I get an error saying "bad request". Maybe I'm missing something obvious in the definition. I was thinking to open another topic for it, but now that you mention it, I should take advantage right now :)

Ok let's go by parts. First, I need to find a way anyway to retrieve those clicks using these selectors, because our company want to see both approaches working, so please, if you can help me with that, I will really appreciate it.

Now... about the reporting feature, this is what I am trying to do, following a combination of these instructions and this example:


            string authToken = "xxxxxxx";
            string clientId = "xxxxxx";
            string fileName = "prueba";
            string developerToken = "xxxxxx";
               
            var request = WebRequest.Create(URL) as HttpWebRequest;
            request.ContentType = "application/x-www-form-urlencoded";
            request.Method = "POST";
            request.Headers.Add("Authorization", "Bearer " + authToken );
            request.Headers.Add("developerToken", developerToken);
            request.Headers.Add("clientCustomerId", clientId);

            string xml =
                @"<reportDefinition>
                       <selector>
                        <fields>CampaignId</fields>
                        <fields>Id</fields>
                        <fields>Impressions</fields>
                        <fields>Clicks</fields>
                        <fields>Cost</fields>
                        <predicates>
                          <field>Status</field>
                          <operator>IN</operator>
                          <values>ENABLED</values>
                          <values>PAUSED</values>
                        </predicates>
                      </selector>
                      <reportName>Custom Adgroup Performance Report</reportName>
                      <reportType>ADGROUP_PERFORMANCE_REPORT</reportType>
                      <dateRangeType>LAST_7_DAYS</dateRangeType>
                      <downloadFormat>CSV</downloadFormat>
                    </reportDefinition>";

            using (var sw = new StreamWriter(request.GetRequestStream()))
            {
                sw.Write("__rdxml=" + HttpUtility.UrlEncode(xml));
            }

            using (var httpWebResponse = request.GetResponse() as HttpWebResponse)
            {
                if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                {
                    using (Stream stream = httpWebResponse.GetResponseStream())
                    {
                        using (FileStream fileStream = File.Create(string.Format("{0}.csv", fileName)))
                        {
                            stream.CopyTo(fileStream);
                        }
                    }
                }
            }

I replaced the AuthToken, clientId and the Developer Token just for security. When I run this code, I get an exception saying "Bad Request"...

Example: 


If I'm missing something obvious, just bare with me, because this is my first HTTP request, and first time working with Google Api also.

Can you point me into the right direction? Why I receive the exception of bad request??? Also, there is a way to retrieve those clicks using these?

I will be kinda staring at my monitor waiting for your answer hehe.

Thank you sir.

Thanet Knack Praneenararat (AdWords API Team)

unread,
Mar 26, 2015, 11:28:21 AM3/26/15
to adwor...@googlegroups.com
Hi Samuel,

Could you please tell me why you would like to use these selectors as well?
I am still checking with my colleagues about this, but it seems reporting feature suits the purpose of getting statistics, such as impressions and number of clicks, much more.

For those selectors you mentioned, I think the main purpose of them is to just get the properties of entities themselves, not statistics around them.
But please wait until I get more information about the design of these selectors.

Regarding your second question, I'm afraid that it may be difficult for us to debug your code according to security and privacy concerns.
Could you please re-check your access token, developer token and client customer ID?
If you can provide SOAP request & response logs, that would be much easier for us to debug together. (Please be sure to strip your personal information off)

For now, I recommend you to try our code example first to see if everything is fine before trying external code example.
Though you don't need to use client libraries all the time, they may be a good start to see if your settings have no problems. :-)

Cheers,
Thanet, AdWords API Team

Samuel Otero

unread,
Mar 26, 2015, 4:52:48 PM3/26/15
to adwor...@googlegroups.com
Again Mr. Thanet, thank you so much for your fast answer.

I'm really trying to get into this. Here is what I have done so far:

I decided to keep working on the code example that I showed you. I know that you recommended me your code example, but mine seems to be a little bit more straightforward. 

I downloaded Fiddler to check request and response logs. Here is what I got:

RAW Request:

Content-Type: application/x-www-form-urlencoded
Authorization: Bearer ****
developerToken: ****
clientCustomerId: ****
Content-Length: 1180
Expect: 100-continue
Connection: Keep-Alive

__rdxml=%3creportDefinition%3e%0d%0a+++++++++++++++++++++++%3cselector%3e%0d%0a++++++++++++++++++++++++%3cfields%3eCampaignId%3c%2ffields%3e%0d%0a++++++++++++++++++++++++%3cfields%3eId%3c%2ffields%3e%0d%0a++++++++++++++++++++++++%3cfields%3eImpressions%3c%2ffields%3e%0d%0a++++++++++++++++++++++++%3cfields%3eClicks%3c%2ffields%3e%0d%0a++++++++++++++++++++++++%3cfields%3eCost%3c%2ffields%3e%0d%0a++++++++++++++++++++++++%3cpredicates%3e%0d%0a++++++++++++++++++++++++++%3cfield%3eStatus%3c%2ffield%3e%0d%0a++++++++++++++++++++++++++%3coperator%3eIN%3c%2foperator%3e%0d%0a++++++++++++++++++++++++++%3cvalues%3eENABLED%3c%2fvalues%3e%0d%0a++++++++++++++++++++++++++%3cvalues%3ePAUSED%3c%2fvalues%3e%0d%0a++++++++++++++++++++++++%3c%2fpredicates%3e%0d%0a++++++++++++++++++++++%3c%2fselector%3e%0d%0a++++++++++++++++++++++%3creportName%3eCustom+Adgroup+Performance+Report%3c%2freportName%3e%0d%0a++++++++++++++++++++++%3creportType%3eADGROUP_PERFORMANCE_REPORT%3c%2freportType%3e%0d%0a++++++++++++++++++++++%3cdateRangeType%3eLAST_7_DAYS%3c%2fdateRangeType%3e%0d%0a++++++++++++++++++++++%3cdownloadFormat%3eCSV%3c%2fdownloadFormat%3e%0d%0a++++++++++++++++++++%3c%2freportDefinition%3e

And here is the response:

HTTP/1.1 400 Bad Request
Content-Type: text/xml
Date: Thu, 26 Mar 2015 20:02:41 GMT
Expires: Thu, 26 Mar 2015 20:02:41 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked

e1
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><reportDownloadError><ApiError><type>AuthenticationError.OAUTH_TOKEN_INVALID</type><trigger>&lt;null&gt;</trigger><fieldPath></fieldPath></ApiError></reportDownloadError>
0


Now, I have a couple of things that I would like to point out.

1. I don't know why my request shows all of those weirds "%3e%0d%0a++" characters. I am not very familiar with these kind of request, and I don't really know if that it's ok or it is not.

2. I can notice that the response clearly reads: AuthenticationError.OAUTH_TOKEN_INVALID. That gets me and I don't fully understand why it is invalid. That's the same token that I use to run this selector fields and it works flawless. This topic on this very forum has a discussion of the situation. One think that I noticed in the discussion, is that a Refresh Token (what I use in my web.config file, example: <add key='OAuth2RefreshToken' value='***' />) is not the same think as the Access Token. There is when I get lost. The OAuth2 Token Generator gives me a Refresh Token... not an "Access Token" doesn't it? 

Maybe the problem here lies in the type of application that I chose to create my first token. I created a Client Id and a Client Secret for a "Native Application"... not a web application... but, it really has something to do with this? Or I'm just missing what should be an obvious difference between a Refresh and an Access Token?

What do you think that should be the next steps for me in order to deal with the "AuthenticationError.OAUTH_TOKEN_INVALID" error? Again, I used the same refresh token which I used while testing the Selector Fields... and those one works. What I am missing? I feel that I'm mixing to entirely different type of tokens.

I will be waiting for your clarification and again, thank you so much for your willingness to help.

- Sam

Thanet Knack Praneenararat (AdWords API Team)

unread,
Mar 27, 2015, 3:12:24 AM3/27/15
to adwor...@googlegroups.com
Hi Samuel,

First, let me update about Selectors that you seem prefer to use to reporting feature.
According to my colleagues, the reason why Selectors do not expose many statistics (e.g., number of clicks) is because of technical issues of underlying technologies.
That's why we created a reporting function so that users can get their statistics much faster and the burdens on related machines are reduced.

In short, if you would like to get statistics about campaigns, for example, the only way for now is to use reporting feature of the API.

Regarding your questions about your codes, 
  1. Strange symbols seem to be the result of URL encoding. I don't think that affects what you would like to do in this program.
  2. For the access token vs refresh token, they DO differ. Access token is what should be specified inside request headers of calls to API. 
    On the other hand, refresh token is used to get access token when the access token is expired, on behalf of the user. I recommend you to review the concept on this page.
By the way, one reason I highly recommend you to try using our code example is because it is customized and tested already so you can get your jobs done (or at least get started) quite easily.
Another good aspect of using the code example in this case is that refresh token is used to get new access tokens (when they are expired) on your behalf automatically

That's why you don't need to specify access token information in App.config--only refresh token is enough.
However, to call reporting function an access token is still needed. 
Therefore, when you specify refresh tokens instead of access tokens, they do not work.

If you still would like to use access tokens, please follow this guide about how to retrieve them.
Please beware that access tokens may get expired and you may need to retrieve a new one every time.

Finally, you can implement to use your refresh token to get new access tokens by yourself as well, 
but that would re-invent the wheel of our client library. :-)

Best,
Thanet, AdWords API Team

Samuel Otero

unread,
Mar 30, 2015, 5:13:50 PM3/30/15
to adwor...@googlegroups.com
Hello again Mr. Thanet

"In short, if you would like to get statistics about campaigns, for example, the only way for now is to use reporting feature of the API". <- That's the line that I needed from you to show to my superiors, thank you! hehe

Ok now, let's get into this. I need just one more reply for help.

With the automation of the access token issue already written in your code example, basically, finally, you sold it to me. That project seems to work flawless... the only thing is that when I download I report, I get nothing :(

Let me explain. The interface in the Default.aspx let you do some things. One of them is to retrieve a list of campaigns after entering a client id. It works, and the query responde with my test campaign. That works well. Now, when I try to download a simple report to view a little bit of information of that very same campaign, the report downloads blank.

Here is my code:

 ConfigureUserForOAuth();

      ReportDefinition definition = new ReportDefinition();

      definition.reportName = "CAMPAIGN_PERFORMANCE_REPORT";
      definition.reportType = ReportDefinitionReportType.CRITERIA_PERFORMANCE_REPORT;
      definition.downloadFormat = DownloadFormat.CSV;
      definition.dateRangeType = ReportDefinitionDateRangeType.ALL_TIME;

      // Create selector.
      Selector selector = new Selector();
      selector.fields = new string[] {"CampaignId", "CampaignStatus", "CampaignName"};

      //Predicate predicate = new Predicate();
      //predicate.field = "Status";
      //predicate.@operator = PredicateOperator.IN;
      //predicate.values = new string[] { "ENABLED", "PAUSED" };
      //selector.predicates = new Predicate[] { predicate };

      definition.selector = selector;
      definition.includeZeroImpressions = true;

      string filePath = ExampleUtilities.GetHomeDir() + Path.DirectorySeparatorChar + "prueba.csv";

      try
      {
          ReportUtilities utilities = new ReportUtilities(user, "v201502", definition);
          using (ReportResponse response = utilities.GetResponse())
          {
              response.Save(filePath);
          }
          //Console.WriteLine("Report was downloaded to '{0}'.", filePath);
          ClientScript.RegisterStartupScript(this.GetType(), "yourMessage", "alert('" + "File Downloaded!" + "');", true);
      }
      catch (Exception ex)
      {
          throw new System.ApplicationException("Failed to download report.", ex);
      }

I even commented the "predicate" part, and the "definition.includeZeroImpressions = true;"  line is there, so I suppose to be receiving a .csv file with a least one campaign, but what I get instead is a blank .csv, only showing the headers specified in the selector. Same thing happens if I download it in xml format. I receive an xml with the right column names, but without values.

What I'm doing wrong? Maybe I'm missing one last obvious thing? I'm using the wrong report? That should not be an issue anyway, as "definition.dateRangeType = ReportDefinitionDateRangeType.ALL_TIME;" and "definition.includeZeroImpressions = true;" lines should be enough to retrieve everything anyway.

I will be waiting for another reply. I'm just a couple of lines away maybe to finish my part of the project. Thank you again for pointing me in the right direction.

- Sam

Thanet Knack Praneenararat (AdWords API Team)

unread,
Mar 30, 2015, 11:15:16 PM3/30/15
to adwor...@googlegroups.com
Hi,

Please review this page (section Mandatory fields) about reporting concepts. :-)

Your code merely hasn't included any metrics in the selector field list, thus nothing is returned.
Try including at least one metric, e.g., clicks, impressions, and run again.

Best,
Thanet, AdWords API Team

Samuel Otero

unread,
Apr 1, 2015, 10:37:46 AM4/1/15
to adwor...@googlegroups.com
Thank you so much for your help. Now I am finally able to retrieve what I need. I will be opening another thread with a question about the reports itself.

- Sam
Reply all
Reply to author
Forward
0 new messages