Opteo/google-ads-node

๐Ÿ˜” Cannot use ConversionActionServiceClient and really would appreciate some help

Sotacan opened this issue ยท 4 comments

I'm submitting a ...

  • bug report
  • feature request
  • question about the decisions made in the repository
  • question about how to use this project

Summary

No matter what I do I can't get a conversion_action object accepted by conversionActions.create(). (These are built on top of ConversionActionServiceClient)

This is for a client and I would really appreciate some help, am willing to pay for some mentorship if need be, thanks!

I am trying to use this code:
customer.conversionActions.create(conversion_action);

I get this issue:
Error: The required field was not present.

Here is a photo of the conversion_action object I'm trying to use:
https://i.gyazo.com/2d987777c1a091339801114bb69ca30b.jpg

Here are the docs for the ConversionAction Object structure:

Here are the docs for this create ConversionAction API:

I have tried every combination I could think of but even with all fields uncommented it shows this issue.

Examples:
With all fields uncommented, I get this same error.
With all fields uncommented except Immutable ones, I get this same error.
With all fields uncommented except Immutable and id, I get this same error.
With all fields uncommented except Immutable and owner_customer, I get this same error.
With all fields uncommented except Immutable and owner_customer, I get this same error.
and many more combos...

Other information

//google-apis-test.js

const { GoogleAdsApi } = require('google-ads-api');

const client = new GoogleAdsApi({
    client_id: 'client_id',
    client_secret: 'client_secret',
    developer_token: 'developer_token',
});

const customer = client.Customer({
    customer_account_id: 'ADWORDS-ACCOUNT-ID',
    login_customer_id: 'MANAGER-ACCOUNT-ID', // Optionally provide a login-customer-id
    refresh_token: 'TOKEN',
});

// Error: The required field was not present.
const conversion_action = {
    //resource_name: '', //Immutable
    //id: 420420420, //Output only
    attribution_model_settings: {
        attribution_model: 101//,
        //data_driven_model_status: 5 //Output only
    },
    category: 4,
    click_through_lookback_window_days: 30,
    counting_type: 3,
    include_in_conversions_metric: true,
    name: 'My API Created conversion action',
    //owner_customer: 'customers/9105817791', //Output only
    phone_call_duration_seconds: 60,
    status: 2,
    //type: 0, //Immutable
    value_settings: {
        always_use_default_value: false,
        default_currency_code: 'USD',
        default_value: 1
    },
    view_through_lookback_window_days: 1,
    //tag_snippets: [], //Output only
    app_id: ''
  };
  
// Passing in a single entity to create
const conversionActionResult = customer.conversionActions.create(conversion_action);

setTimeout(async () => {
    console.log(await conversionActionResult);
}, 5000);
Sotacan-MBP:google-api-tests sotacan$ node google-apis-test.js
(node:40797) UnhandledPromiseRejectionWarning: Error: The required field was not present.
    at ConversionActionService.<anonymous> (/Users/sotacan/Documents/Projects/contract-work/Google-Tracker-Shopify-App/google-api-tests/node_modules/google-ads-api/build/services/service.js:199:23)
    at Generator.throw (<anonymous>)
    at rejected (/Users/sotacan/Documents/Projects/contract-work/Google-Tracker-Shopify-App/google-api-tests/node_modules/google-ads-api/build/services/service.js:6:65)
(node:40797) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:40797) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:40797) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
(node:40797) UnhandledPromiseRejectionWarning: Error: The required field was not present.
    at ConversionActionService.<anonymous> (/Users/sotacan/Documents/Projects/contract-work/Google-Tracker-Shopify-App/google-api-tests/node_modules/google-ads-api/build/services/service.js:199:23)
    at Generator.throw (<anonymous>)
    at rejected (/Users/sotacan/Documents/Projects/contract-work/Google-Tracker-Shopify-App/google-api-tests/node_modules/google-ads-api/build/services/service.js:6:65)
(node:40797) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
Sotacan-MBP:google-api-tests sotacan$ 

Hi @Sotacan, it's pretty late here right now, but I'll take a look tomorrow and get back to you!

Hi @Sotacan, I've taken a look and found a solution to your issue.

It looks as if you were not correctly specifying the type field of the conversion action object. The value 0 means UNSPECIFIED, which I assume isn't allowed in Google Ads? (I may be wrong here). If I set that to another value, the request appears to work.

Using this as the conversion action object works for me:

const conversion = {
    name: 'my-conversion-action',
    status: enums.ConversionActionStatus.ENABLED,
    type: enums.ConversionActionType.AD_CALL,
    category: enums.ConversionActionCategory.PURCHASE,
    include_in_conversions_metric: true,
    click_through_lookback_window_days: 30,
    // view_through_lookback_window_days: 1,
    attribution_model_settings: {
        attribution_model: enums.AttributionModel.GOOGLE_ADS_LAST_CLICK,
    },
    value_settings: {
        // always_use_default_value: false,
        default_currency_code: 'USD',
        default_value: 1,
    },
}

I've commented out two fields which appear to cause problems, perhaps they can't be set when initially creating the conversion action.

I'd highly recommend using the enums import instead of using the direct values, e.g.

status: enums.ConversionActionStatus.ENABLED, // good
status: 1, // bad

The enums module can be imported with GoogleAdsApi, like so:

const { GoogleAdsApi, enums } = require('google-ads-api');

I would also strongly recommend using TypeScript if possible. This will allow you to use the types import, which makes working with theses complex objects much easier.

You can also get much better debugging information if you wrap your code in a try/catch block, and avoid using the setTimeout:

try {
    const result = await customer.conversionActions.create(conversion_action)
    console.log(result)
} catch (err) {
    console.log('Error creating conversion action:')
    // The err object includes details on which particular key is missing
    console.log(err)
}

Let me know if you still have problems!

Hmm i have the same issue, and thanks enums is sweet.

https://gyazo.com/26afd8a417a05645240fb9a79829d04c

So it looks like the phone_call_duration_seconds is now causing issues. If you use a try/catch block like I mentioned previously, this error would be visible in your terminal!

It seems to not allow phone_call_duration_seconds to be set when using the type: enums.ConversionActionType.WEBPAGE. I managed to get it working when setting the type to enums.ConversionActionType.AD_CALL.

Again, I'm not an expert in all the settings for conversion actions, so it may be worth getting in contact with the Google Ads API support team.