Search code examples
google-analyticsgoogle-analytics-apigoogle-analytics-filters

Why does Analytics Data API V1 Beta not conform to the REST spec?


I'm adding GTM and GA4 to some website apps that need to produce detailed stats on the click-throughs of ads per advertiser. This looks infeasible with standard GA reporting so am using the PHP implementation of Analytics Data API V1 Beta. Since there are few examples (eg analyticsdata/quickstart.php) of V1 reporting using PHP, I am translating other classes and operands from the REST API’s JSON .

<?php
namespace Google\Analytics\Data\V1beta;
require 'vendor/autoload.php';

$property_id = '<redacted>';

putenv('GOOGLE_APPLICATION_CREDENTIALS=Keyfile.json');

$client = new BetaAnalyticsDataClient();

// Make an API call.
$response = $client->runReport([
    'property' => 'properties/' . $property_id,
    
    'dateRanges' => [
        new DateRange([
            'start_date' => '2021-04-01',
            'end_date' => 'today',
        ]
        ),
    ],
    'dimensions' => [new Dimension(
        [
           'name' => 'customEvent:link_classes'
        ]
    ),
    ],
        
     'dimensionFilter'=>[new FilterExpression(
           [
           'filter'=>[new Filter(
           [
          'field_name' => 'customEvent:Classes',
          'string_filter' => [new Filter\StringFilter(
          [
          'match_type'=> '1',
          'value'=> 'AdvertA',
          'case_sensitive'=> false 
          ])]])]])],
    
    'metrics' => [new Metric(
        [
            'name' => 'eventCount',
        ]
    )
    ]
]);
etc

The Quickstart example works but has endless trouble when a dimensionFilter is added. For example, match_type should be an enum of one of a few character strings (EXACT, CONTAINS and so on). The JSON definition of match_type only shows the strings (enum 'members') and not any associated values (which would usually be integers). The GA4 migration guide has an example with

 "matchType": "BEGINS_WITH"  

PHP doesn’t have ‘enum’ but the equivalent would be to select one string and assign it to match_type (vide above). Wrong: StringFilter falls over unless it is given an integer operand, presumably the ordinal number of the desired match in the enum match string (and is the first one 0 or 1?). My understanding of the JSON schema was that an 'enum' list simply restricted the result to one of the unique operands, with an optional check on the operand type. (By comparison, the Python enumerate function returns an object containing a list of pairs with the ordinal number of an operand preceding the operand).

Custom dimensions appear not to conform to the API’s JSON. In Analytics, I specify a custom dimension with a dimension Name of Classes and User Property/Parameter of link_classes**. However... in the API, dimension Name has to be customEvent:link_classes and not customEvent:Classes. Otherwise it falls over with ‘Field customEvent:Classes is not a valid dimension’ This occurs also when defining field_name in a Filter within a Filter Expression. So is the API dimension Name not the name of the Analytics dimension Name but actually the Property/Parameter of an Analytics descriptive name? In one place I read the latter: "Custom dimensions are specified in an API report request by the dimension's parameter name and scope." but elsewhere it is implied that Name is the dimension name, e.g. /devguides/reporting/data/v1/advanced: "dimensions": [{ "name": "customUser:last_level" }]

Finally, even falling in line with what the developers have implemented, dimensionFilter falls over with ‘Expect Google\Analytics\Data\V1beta\Filter\StringFilter

It is Beta code but one would not expect overt deviations from the REST spec so perhaps I am reading the spec wrongly. Does anyone else have this problem?

** GTM has a ‘Click - Just Links’ trigger where the ‘click URL’ ‘contains’ the advertiser’s URL. The Classes custom dimension in the API dimension Filter has the class values of the adverts click-through links.


Solution

  • To answer the first part of your question, I believe the correct way to use an enum in PHP would be:

    'match_type' => Filter\StringFilter\MatchType::BEGINS_WITH

    As for the second question. Per the API schema documentation the name of a custom dimension is constructed as customEvent:parameter_name for event scoped dimensions and customUser:parameter_name for user scoped dimensions. Where parameter_name, as you correctly noted, is not a descriptive name, but rather the event parameter name. In your example you seem to be using a user scoped dimension, so the dimension name in the API should be customUser:link_classes.

    Here is a complete example that seems to be running fine:

    require 'vendor/autoload.php';
    
    use Google\Analytics\Data\V1beta\BetaAnalyticsDataClient;
    use Google\Analytics\Data\V1beta\DateRange;
    use Google\Analytics\Data\V1beta\Dimension;
    use Google\Analytics\Data\V1beta\FilterExpression;
    use Google\Analytics\Data\V1beta\Filter;
    use Google\Analytics\Data\V1beta\Metric;
    
    /**
     * TODO(developer): Replace this variable with your Google Analytics 4
     *   property ID before running the sample.
     */
    $property_id = 'YOUR-GA4-PROPERTY-ID';
    
    
    $client = new BetaAnalyticsDataClient();
    
    // Make an API call.
    $response = $client->runReport([
        'property' => 'properties/' . $property_id,
        'dateRanges' => [
            new DateRange([
                'start_date' => '2020-03-31',
                'end_date' => 'today',
            ]),
        ],
        'dimensions' => [new Dimension(
            [
                'name' => 'customUser:link_classes'
            ]),
        ],
    
        'dimensionFilter' => new FilterExpression(
            [
                'filter' => new Filter(
                    [
                        'field_name' => 'customUser:link_classes',
                        'string_filter' => new Filter\StringFilter(
                            [
                                'match_type' => Filter\StringFilter\MatchType::BEGINS_WITH,
                                'value' => 'AdvertA',
                                'case_sensitive' => false
                            ]
                        )
                    ])
    
            ]),
    
        'metrics' => [new Metric(
            [
                'name' => 'eventCount',
            ]
        )
        ]
    ]);