opteo / google-ads-api Goto Github PK
View Code? Open in Web Editor NEWGoogle Ads API client library for Node.js
Home Page: https://opteo.com
License: MIT License
Google Ads API client library for Node.js
Home Page: https://opteo.com
License: MIT License
I already have all my oauth credentials ready, I may be a complete brainlet because I can't figure out how to get a successful request/response through...
This repo only shows basic use case but no real setup and implementation example...
Is there a NodeJS example floating around somewhere that I can look at? Can I "gift" someone fifty bucks for an hour of their time to help me get a request through?
This is a seemingly esoteric subject as there are no guides online, and the official google docs are much less than helpful for a beginner, there's really quite sparse information over there.
Account management or creation
https://developers.google.com/adwords/api/docs/guides/accounts-overview
Can we add this also in the api
Is there a timeline for exposing GenerateForecastMetricsRequest for KeywordPlans in the API? I can see that it's generated in google-ads-node so I'm guessing it's possible to use it straight from that library. But, it would be nice if it would be exposed here as well. I'm happy to help out if anyone can point to an example of how to get a service from google-ads-node into this library.
N/A
Hi there,
thanks for the great library! Sadly the when querying for any resource that uses url_custom_parameters I get back an array with objects of values. The official google API should return the keys of the custom parameter aswell. Only having a value without the key is not very helpful. Do I have to specify something to get it?
Here you can find the google docs: https://developers.google.com/adwords/api/docs/reference/v201809/AdGroupService.CustomParameter.html
Here is a sample query:
const results = await customer.report({
entity: 'ad_group_criterion',
attributes: ['ad_group_criterion.url_custom_parameters'],
});
and the result:
[
{
"ad_group_criterion": {
"resource_name": "customers/<my-customer-id>/adGroupCriteria/<ad-group-criterion-id",
"url_custom_parameters": [
{
"value": "value1"
},
{
"value": "value2"
}
]
}
}
]
Hey there,
I'm wanting to update an existing account budget and get back the following error:
TypeError: operation.setUpdate is not a function
at AccountBudgetProposalService.
I run the following code (using version 3.2.0):
customer.accountBudgetProposals.update({
resource_name: accountBudget,
proposal_type: 4
});
Not too sure why I can't update, I had a similar issue when trying to update billing setups (was not possible in the api). Looking at the docs this should be possible :)
Am I missing something here?
Thanks
I wasn't able to find the AssetService inside the documentation but I did find it in the code. I was wondering if this was done on purpose.
I'm running client.customerClients.list()
, but it's entities missing descriptive_name
property.
I'm getting only these properties in response: resource_name
, client_customer
, hidden
, level
PHP example shows that the fields should be there:
https://github.com/googleads/google-ads-php/blob/master/examples/AccountManagement/GetAccountHierarchy.php#L128
Is there a way to get the pages of a report instead of waiting for all the pages to come back? One of our clients has a couple hundred thousand keywords. Trying to wait for every page to return takes up a ton of memory, and takes quite a while causing time outs in lambda. I was wondering if there was a way to collect/return the results as they are returned from the api instead of after every page has completed. Maybe a callback that can be inserting into the page looping process?
When running the default examples, I get an error "customer.search is not a function"
However, customer.query works fine.
I'm not sure if this is a documentation bug or a software bug...
I'm not able to find any functionality about skipping the first x
amount of items. I do see that campaigns has a LIMIT
key but it would be nice to have something like SKIP or OFFSET too like in SQL. e.g:
customer.campaign.list({
skip: 10,
limit: 10,
})
โฌ Gets result 10 to 20.
There are only read endpoints for CustomerClient, how would I add CreateCustomerClientRequest?
Missing
CreateCustomerClientRequest
Request message for CustomerService.CreateCustomerClient.
https://developers.google.com/google-ads/api/reference/rpc/google.ads.googleads.v2.services#createcustomerclientrequest
Hi guys,
I'm struggling to add a keyword.
Even the example doesn't work for me.
My code:
const { GoogleAdsApi, enums } = require('google-ads-api')
// Make sure you pass in valid authentication details!
const client = new GoogleAdsApi({
client_id: '79573XXXXXXXXXXXXXXXXXXXX3.apps.googleusercontent.com',
client_secret: 'sGCJRDXXXXXXXXXXXXXXXXXXXXQN1pq4',
developer_token: 'hquXXXXXXXXXXXXXXXXXXXXB3jzPg',
})
async function main() {
const customer = client.Customer({
customer_account_id: '111222333',
login_customer_id : '4445556666', // MCC
refresh_token: "1/oWh6IPXXXXXXXXXXXXXXXq4P1X-M"
})
// Bonus: If you're using Typescript, set the type here to "types.Keyword" for autocomplete!
const keyword = {
ad_group: 'customers/111222333/adGroups/78901234567',
status: enums.AdGroupCriterionStatus.ENABLED,
text: 'hotels london',
match_type: enums.KeywordMatchType.EXACT,
}
try {
const { results } = await customer.adGroupCriterion.create(keyword)
/*
The newly created ad group criterion will have a resource name in the following format:
"customers/{customer_id}/adGroupCriteria/{ad_group_id}~{criterion_id}"
*/
} catch (err) {
if (err.code.adGroupCriterionError === enums.AdGroupCriterionError.INVALID_KEYWORD_TEXT) {
console.log(`Keyword with text "${keyword.text}" is invalid!`)
} else {
console.log(err);
}
}
}
main()
My output:
{ Error: The required field was not present in the resource.
at AdGroupCriterionService.<anonymous> (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/google-ads-api/build/services/service.js:142:23)
at Generator.throw (<anonymous>)
at rejected (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/google-ads-api/build/services/service.js:5:65)
at <anonymous>
code:
{ requestError: 0,
biddingStrategyError: 0,
urlFieldError: 0,
listOperationError: 0,
queryError: 0,
mutateError: 0,
fieldMaskError: 0,
authorizationError: 0,
internalError: 0,
quotaError: 0,
adError: 0,
adGroupError: 0,
campaignBudgetError: 0,
campaignError: 0,
authenticationError: 0,
adGroupCriterionError: 0,
adCustomizerError: 0,
adGroupAdError: 0,
adSharingError: 0,
adxError: 0,
assetError: 0,
biddingError: 0,
campaignCriterionError: 0,
collectionSizeError: 0,
countryCodeError: 0,
criterionError: 0,
customerError: 0,
dateError: 0,
dateRangeError: 0,
distinctError: 0,
feedAttributeReferenceError: 0,
functionError: 0,
functionParsingError: 0,
idError: 0,
imageError: 0,
languageCodeError: 0,
mediaBundleError: 0,
mediaFileError: 0,
multiplierError: 0,
newResourceCreationError: 0,
notEmptyError: 0,
nullError: 0,
operatorError: 0,
rangeError: 0,
recommendationError: 0,
regionCodeError: 0,
settingError: 0,
stringFormatError: 0,
stringLengthError: 0,
operationAccessDeniedError: 0,
resourceAccessDeniedError: 0,
resourceCountLimitExceededError: 0,
adGroupBidModifierError: 0,
contextError: 0,
fieldError: 2,
sharedSetError: 0,
sharedCriterionError: 0,
campaignSharedSetError: 0,
conversionActionError: 0,
conversionAdjustmentUploadError: 0,
conversionUploadError: 0,
headerError: 0,
databaseError: 0,
policyFindingError: 0,
enumError: 0,
keywordPlanError: 0,
keywordPlanCampaignError: 0,
keywordPlanNegativeKeywordError: 0,
keywordPlanAdGroupError: 0,
keywordPlanKeywordError: 0,
keywordPlanIdeaError: 0,
accountBudgetProposalError: 0,
userListError: 0,
changeStatusError: 0,
feedError: 0,
geoTargetConstantSuggestionError: 0,
feedItemError: 0,
labelError: 0,
billingSetupError: 0,
customerClientLinkError: 0,
customerManagerLinkError: 0,
feedMappingError: 0,
customerFeedError: 0,
adGroupFeedError: 0,
campaignFeedError: 0,
customInterestError: 0,
extensionFeedItemError: 0,
adParameterError: 0,
feedItemValidationError: 0,
extensionSettingError: 0,
feedItemTargetError: 0,
policyViolationError: 0,
mutateJobError: 0,
partialFailureError: 0,
policyValidationParameterError: 0 },
request:
{ customerId: '8849161347',
operationsList: [ [Object] ],
partialFailure: false,
validateOnly: false },
request_id: 'P0zzq9JTK3piHQocRGo5zg',
failure:
{ Error: 3 INVALID_ARGUMENT: The required field was not present in the resource.
at Object.exports.createStatusError (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/common.js:91:15)
at Object.onReceiveStatus (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:1204:28)
at InterceptingListener._callNext (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:618:8)
at Object.grpc_1.default.ListenerBuilder.withOnReceiveStatus [as onReceiveStatus] (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/google-ads-node/build/lib/interceptor.js:68:17)
at InterceptingListener._callNext (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:618:8)
at Object.grpc_1.default.ListenerBuilder.withOnReceiveStatus [as onReceiveStatus] (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/google-ads-node/build/lib/interceptor.js:151:13)
at InterceptingListener._callNext (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/<USER>/Development/WebstormProjects/<PROJECT>/node_modules/grpc/src/client_interceptors.js:618:8)
code: 3,
metadata: Metadata { _internal_repr: [Object] },
details: 'The required field was not present in the resource.' } }
How to get a helpful error message?
Just received
Error: 3 INVALID_ARGUMENT: The required field was not present in the resource.
So which required field is missing?
BTW: If I comment out the status row
const keyword = {
ad_group: 'customers/8849161347/adGroups/68449099820',
// status: enums.AdGroupCriterionStatus.ENABLED,
text: 'hotels london',
match_type: enums.KeywordMatchType.EXACT,
}
The example works. The keyword is created.
I'm looking forward to any hint.
Thanks a lot.
Best,
Christian
When not defining a limit
in report
, limit will get set implicitly to 0 and pagination will always hit
Line 88 in 361c5a5
Hey, I see that you do provide support to add location in code? (probably in customer.ts file) but I can't see anything in docs and am unable to comprehend how I can set location.
I understand that docs are in the process of being updated, but can someone please help me in finding the way to add location till that time.
How does one get a refresh token?
Refresh token: You'll get this token when somebody authorises you to query their adwords account via OAuth.
Is not thorough documentation.
The REST API has a way to create multiple objects atomically in a single request by using temporary IDs. That way, if one of the requests fails, they all fail and you won't have to go back and delete the ones that worked to maintain consistency. One example is creating campaign budgets and campaigns at the same time. The request would look something like this:
// POST /v1/customer/123456789/googleAds:mutate
mutate_operations: [
{
campaign_budget_operation: {
create: { name: "test budget", resource_name: "customers/123456789/campaignBudgets/-1" }
},
campaign_operation: {
create: { name: "test campaign", campaign_budget: "customers/123456789/campaignBudgets/-1", resource_name: "customers/123456789/campaigns/-2" }
}
},
...etc
]
I don't know that there's a way to handle such a request in gRPC. But, it might not be a terrible idea to expose a mutate method that allows raw mutations such as this that otherwise wouldn't be possible. Would you be open to having such a method in the new API?
I'm trying to use this package without asking an user to authenticate using a Web interface. My question here is: does it work with service keys based authentication?
Thanks you!
Waiting on Opteo/google-ads-node#10 Google Ads API v1.2.0 is now ready to use in the latest google-ads-node release (1.11.0)
Release Notes: https://developers.google.com/google-ads/api/docs/release-notes#120_2019-04-29
i was Trying to make Campagin i had Create Campagin Budget Successfully Before , but now i had that error and i can't pass it .
code :
const campaign = {
ad_serving_optimization_status: 2, // Ad serving is optimized based on CTR for the campaign.
advertising_channel_type: 7, // Multi Channel
bidding_strategy_type: 12, // Target impression Share
campaign_budget: 'customers/7352765242/campaignBudgets/2082563969',
end_date: '2037-12-30',
start_date: '2019-06-09',
experiment_type: 2, // Regular Campagin not testone
geo_target_type_setting: { negative_geo_target_type: 2, positive_geo_target_type: 2 },//Dont Care
labels: [],
name: 'Loai abdalslam Pin-offer #1',
network_settings: {
target_content_network: true,
target_google_search: false,
target_partner_search_network: false,
target_search_network: false,
},
payment_mode: 2, // By Click
selective_optimization: { conversion_actions: [] },
serving_status: 2,//Serving
status: 2,
}
const result = customer.campaigns.create(campaign)
result.then(function(){
console.log(result)
})
and error :
UnhandledPromiseRejectionWarning: Error: Unauthorized CREATE operation in invoking a service's mutate method.
at CampaignService.<anonymous> (/home/loaii/personal/pin-offer/tasks/google-ads-api/google-ads/node_modules/google-ads-api/build/services/service.js:171:23)
at Generator.throw (<anonymous>)
at rejected (/home/loaii/personal/pin-offer/tasks/google-ads-api/google-ads/node_modules/google-ads-api/build/services/service.js:5:65)
(node:16906) 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(). (rejection id: 1)
(node:16906) [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.
letset version of google ads api
all things is working successfully but please help me to pass this error today ..
I'm unable to create Video Ad in existing Skippable in-stream Ad Group in Video Campaign - it fails with an error "Internal error encountered".
But in a same time I don't have any issues with managing Display Ads.
Am I missed something? I'll appreciate any advice.
Thank you
[email protected]
[email protected]
[email protected]
AdGroupAd:
{
"ad_group": "customers/1234567890/adGroups/0987654321",
"status": 2,
"ad": {
"type": 12,
"name": "Unspecified",
"final_urls": [
"https://example.com?__noscript=true"
],
"tracking_url_template": "https://example.com?gg_campaign_id={campaignid}&gg_adgroup_id={adgroupid}&gg_network={network}&gg_device={device}&gg_gclid={gclid}&gg_creative={creative}",
"video_ad": {
"media_file": "customers/1234567890/mediaFiles/1123456789",
"in_stream": {
"companion_banner": "customers/1234567890/mediaFiles/1223456789"
}
}
}
}
Response:
{
"code": 13,
"metadata": {
"_internal_repr": {
"google.ads.googleads.v2.errors.googleadsfailure-bin": [
{
"type": "Buffer",
"data": [
10,
41,
10,
2,
80,
2,
18,
31,
65,
110,
32,
105,
110,
116,
101,
114,
110,
97,
108,
32,
101,
114,
114,
111,
114,
32,
104,
97,
115,
32,
111,
99,
99,
117,
114,
114,
101,
100,
46,
26,
2,
42,
0
]
}
],
"grpc-status-details-bin": [
{
"type": "Buffer",
"data": [
8,
13,
18,
27,
73,
110,
116,
101,
114,
110,
97,
108,
32,
101,
114,
114,
111,
114,
32,
101,
110,
99,
111,
117,
110,
116,
101,
114,
101,
100,
46,
26,
114,
10,
67,
116,
121,
112,
101,
46,
103,
111,
111,
103,
108,
101,
97,
112,
105,
115,
46,
99,
111,
109,
47,
103,
111,
111,
103,
108,
101,
46,
97,
100,
115,
46,
103,
111,
111,
103,
108,
101,
97,
100,
115,
46,
118,
50,
46,
101,
114,
114,
111,
114,
115,
46,
71,
111,
111,
103,
108,
101,
65,
100,
115,
70,
97,
105,
108,
117,
114,
101,
18,
43,
10,
41,
10,
2,
80,
2,
18,
31,
65,
110,
32,
105,
110,
116,
101,
114,
110,
97,
108,
32,
101,
114,
114,
111,
114,
32,
104,
97,
115,
32,
111,
99,
99,
117,
114,
114,
101,
100,
46,
26,
2,
42,
0
]
}
],
"request-id": [
"cVjZ2So7RYlQsEKjWhBFWQ"
]
},
"flags": 0
},
"details": "Internal error encountered."
}
Currently the query builder does not support sorting query results by multiple fields.
It should allow ordering by multiple fields with different sort orders like specified in the documentation : https://developers.google.com/google-ads/api/docs/query/ordering-limiting
Moreover, by default DESC sort_order is appended to the order part of the query although the official documentation says that sort order is not mandatory and the default behavior is to sort results ascending.
Line 182 in e99a0f3
I am trying to implement the google-ads-api in my Node Express app. I downloaded the library (npm i google-ads-api), and I am trying to get started with the code below.
const GoogleApiNodeLibrary = require('google-ads-api');
const client = new GoogleApiNodeLibrary.GoogleAdsApi({
client_id: 'XXX',
client_secret: 'XXX',
developer_token: 'XXXX',
});
const customer = client.Customer({
customer_account_id: 'XXX',
login_customer_id: 'XXX',
refresh_token: 'XXX'
});
customer.campaigns.list();
The values I am using for Authentication are all correct. The "login_customer_id:" uses the MCC ID, and the "customer_account_id:" uses one of the accounts ID linked to the MCC account.
When I run this code, I don't get an error. It just take a few seconds and then return "Process finished with exit code 0".
How can I fix this?
When querying any type of simulations (i.e. ad_group_simulation
or campaign_criterion_simulation
) with the report()
method any fields ending in list
are not shown.
This is the list of all the missing fields :
campaign_criterion_simulation.bid_modifier_point_list
ad_group_simulation.cpc_bid_point_list
ad_group_simulation.target_cpa_point_list
ad_group_criterion_simulation.cpc_bid_point_list
When querying the search term performance report and ordering by impressions, the results are only partially sorted. The values do decrease in net value, but they are not completely sorted
I got the bug when call method from Child threads (worker threads),
I'm running nodejs 12.13.0 and when I call Google Api with Protobuf (may relate with C++ native layer),
OS is Windows 10.
FATAL ERROR: v8::HandleScope::CreateHandle() Cannot create a handle without a HandleScope 1: 00007FF66DBE094F napi_wrap+124431 2: 00007FF66DB82696 v8::base::CPU::has_sse+34502 3: 00007FF66DB83356 v8::base::CPU::has_sse+37766 4: 00007FF66E386EBC v8::FunctionTemplate::RemovePrototype+284 5: 00007FF66E26DB95 v8::internal::HandleScope::Extend+53 6: 00007FF66E0E6580 v8::internal::JSReceiver::GetCreationContext+288 7: 00007FF66E36C030 v8::Object::CreationContext+32 8: 00007FF66DBFCE58 node::MakeCallback+40 10: 00007FFE4005ED30 12: 00007FF66DC1FC42 uv_prepare_init+114 13: 00007FF66DC29426 uv_run+262 14: 00007FF66DB4B892 EVP_CIPHER_CTX_buf_noconst+30946 15: 00007FF66DBA9263 node::Start+275
For each campaign in my account, I wish to extract campaign_budget.amount_micros
. However, I cannot figure out a way to do this. If I list all my campaigns, I see that campaign_budget
property is a URL. However, I am stuck at trying to figure out how I could query it.
Also, I will need to update it once I receive the value. I assume that I would struggle with it as well :)
I've run into scenarios when running a query returns the following error "Error: Received message larger than max (9154892 vs. 4194304)"
t CustomerService. (C:\prj\node_modules\google-ads-api\build\services\service.js:205:23)
at Generator.throw ()
at rejected (C:\prj\node_modules\google-ads-api\build\services\service.js:5:65)
Is this project currently/going to remain open source? If so, are you willing to accept pull requests? Thanks.
The google ads documentation shows the ConversionUploadService as having endpoints for UploadCallConversions() and UploadClickConversions() which accept an array of conversions and support partial_failures. The typescript definitions for this client library suggest that only one conversion is accepted at a time:
customer.conversionUploads.uploadClickConversion(conversion: ClickConversion)
customer.conversionUploads.uploadCallConversion(conversion: CallConversion)
Should these not be more like as follows?
customer.conversionUploads.uploadClickConversions(conversions: Array, options?: ServiceCreateOptions)
It would be nice to optionally pass a single constraints object, as opposed to an array of multiple constraint objects.
Before:
const audiences = await gads.report({
entity: 'campaign_criterion',
attributes: ['campaign.id', 'campaign.advertising_channel_type'],
constraints: [
{
'campaign.status': wasd.enums.CampaignStatus.ENABLED,
},
{
'campaign.advertising_channel_type': wasd.enums.AdvertisingChannelType.DISPLAY,
},
{
'campaign.id': 123
}
],
})
After:
const audiences = await gads.report({
entity: 'campaign_criterion',
attributes: ['campaign.id', 'campaign.advertising_channel_type'],
constraints: {
'campaign.status': wasd.enums.CampaignStatus.ENABLED,
'campaign.advertising_channel_type': wasd.enums.AdvertisingChannelType.DISPLAY,
'campaign.id': 123,
},
})
Hey there,
I'm wanting to update an existing billing setup and get back the following error:
TypeError: operation.setUpdate is not a function at BillingSetupService.<anonymous>
I run the following code (using version 3.2.0):
await customer.billingSetups.update({
resource_name: "customers/*****/billingSetups/*****",
start_time_type: TimeType.NOW
});
Not too sure why I can't update, would be amazing to get a hand :)
unhandledRejection Error: connect ETIMEDOUT 216.58.200.237:443
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1056:14) {
errno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect',
address: '216.58.200.237',
port: 443
}
try-catch clause can not handle this error.
the exception was thrown by google-ads-api.
here is my code:
async query(gaqlString) {
try {
const customer = this._getCustomer();
const result = await customer.query(gaqlString);
return this._result(0, 'ok', result);
} catch (err) {
return this._result(-1, err.message || err);
}
}
I noticed that the library wraps some results into objects with key value, instead of returning just raw values.
For instance, when I queried final urls for an ad group ad, I received this array of objects:
[ { value: 'https://www.geoteam.be/nl/steden/aalst' } ]
According to the API documentation, I should receive array of strings that looks like this:
['https://www.geoteam.be/nl/steden/aalst' ]
.
Another example of the issue:
[ { ad_group:
{ resource_name: 'customers/xxx/adGroups/xxx',
cpc_bid_micros: 1000000,
targeting_setting:
{ target_restrictions:
[ { targetingDimension: 3, bidOnly: { value: true } },
{ targetingDimension: 4, bidOnly: { value: false } },
{ targetingDimension: 5, bidOnly: { value: true } },
{ targetingDimension: 6, bidOnly: { value: true } },
{ targetingDimension: 7, bidOnly: { value: false } },
{ targetingDimension: 8, bidOnly: { value: true } },
{ targetingDimension: 9, bidOnly: { value: true } } ] } } } ]
}
Here the library should return booleans for bidOnly.
Release notes: v1.1
To-do:
When using the constraints key-op-val syntax and the val
is undefined
, the error message we give is misleading:
(node:9568) UnhandledPromiseRejectionWarning: Error: must specify { key, op, val } when using object-style constraints
const campaign = {
id: undefined,
};
const campaigns = await customer.campaigns.list({
constraints: [
{
key: "campaign.id",
op: "=",
val: campaign.id,
},
],
});
In this case, we should raise an error message that the val
property is undefined. Something along the lines of "val" field is an undefined value
. Alternatively, we could use TypeScript and make sure val
is typeof not undefined
, to give a compile time warning.
Hi there,
I'm using oAuth so my customers can provide access to their Google Ads accounts, which is working fine to get the refresh token for the Customer
function, but I can't find a way to list the customer_account_id
without them specifying it manually.
customer.Customer({
refresh_token: GOTTHIS,
customer_account_id: NOTGOTTHIS
});
Any ideas?
Hey there ๐,
When I try to create a Custom Interest I get back an error which indicates members aren't being populated but I am passing through params which include a collection of CustomInterestMember objects.
I pass through the following params
{
"type":3,
"name":"I like dogs",
"description":"We love dogs, dogs are the best",
"members":[
{"member_type":2,"parameter":"dog"}
]
}
I get back the following error:
code: { fieldError: 2 },
request:
{ customerId: '4674531019',
operationsList: [ [Object] ],
validateOnly: false },
request_id: 'BQbtQVg1e9ouMxsKPaea9g',
location: 'operations[0].create.members[0]',
failure:
{ Error: 3 INVALID_ARGUMENT: The required field was not present.
It appears that the member list (element 7) is an empty array - we'd expect it to have one element.
'7':
[ { wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } ] },
Is there anything that I am missing here?
The policy_summary
in AdGroupAd
resolved to undefined
.
While debugging protobufs I see the data for this attribute, but it's lost somewhere during converting to JSON.
return client
.report({
entity: 'ad_group_ad',
attributes: ['ad_group_ad.status', 'ad_group_ad.policy_summary'],
constraints
})
Hi!
My application also uses other Google APIs. Ever since starting to use this library, I'm getting 401 errors from other Google libraries using the official Google API.
I'm going to start, but hypothesizing that I'm going to see that each library is using the client id/secret and refresh token to generate their own access tokens which are flapping and locking one another out.
Would it be possible to allow this library to get and manage the access_token, at least, via the official Google Auth library for nodejs? That way it can (hopefully) be managed by a singleton instance dealing with the OAuth-level authentication (or any Google-supported authentication) and play nicer with the rest of the ecosystem?
It appears there is an issue with the interpretation/parsing of deeply nested objects/arrays. I am finding this issue specifically in the structure of AdGroup -> targeting_setting
but it may also exist elsewhere in the API.
Overall this seems to be related to but not necessarily the same as the bug/discussion in closed issue #59. I have observed the following potential issues:
targeting_restrictions: undefined
in the struct of an AdGroup
nested_path
for deeply nested array is being generated as targeting_setting.target_restrictions.targetingDimension
when it appears this should actually be targeting_setting.target_restrictions[<INDEX>].targetingDimension
This bug is being encountered specifically when trying to build AdGroup via API per the structure of the google-ads-api documentation and the native Google Ads API documentation. It appears at least part of the issue is within the handling of the unroll(v)
function on line 84 of google-ads-node/build/lib/utils.js
-- I believe this may need to have the index passed in from the isArray
portion above it and a determination made as to how to structure the nested_path
accordingly.
The following console logs may be helpful:
(Occurs when attempting to build/create AdGroup)
Error: Attempted to set value "3" on invalid path "targeting_setting.target_restrictions.targetingDimension" in resource
at toProtoValueFormat (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:96:15)
at unroll (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:87:19)
at convertToProtoFormat (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:83:26)
at unroll (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:86:19)
at pb.(anonymous function).value.map (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:79:24)
at Array.map (<anonymous>)
at convertToProtoFormat (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:78:36)
at unroll (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:86:19)
at Object.convertToProtoFormat (~/google-ads-api-test/node_modules/google-ads-node/build/lib/utils.js:83:26)
at GoogleAdsClient.buildResource (~/google-ads-api-test/node_modules/google-ads-node/build/lib/client.js:82:41)
(Log of the struct for AdGroup -- note target_restrictions: undefined
which should be an array of objects with targeting_dimension
and bid_only
properties )
{ struct:
{ resource_name: 'string',
id: 'number',
name: 'string',
status: 'enum_AdGroupStatus',
type: 'enum_AdGroupType',
ad_rotation_mode: 'enum_AdGroupAdRotationMode',
base_ad_group: 'string',
tracking_url_template: 'string',
url_custom_parameters: { key: 'string', value: 'string' },
campaign: 'string',
cpc_bid_micros: 'number',
cpm_bid_micros: 'number',
target_cpa_micros: 'number',
cpv_bid_micros: 'number',
target_cpm_micros: 'number',
target_roas: 'number',
percent_cpc_bid_micros: 'number',
explorer_auto_optimizer_setting: { opt_in: 'boolean' },
display_custom_bid_dimension: 'enum_TargetingDimension',
final_url_suffix: 'string',
targeting_setting: { target_restrictions: undefined },
effective_target_cpa_micros: 'number',
effective_target_cpa_source: 'enum_BiddingSource',
effective_target_roas: 'number',
effective_target_roas_source: 'enum_BiddingSource',
labels: 'string' } }
I am actively working on a suitable resolution but would appreciate feedback/assistance from the community and authors in the meantime. I will comment/update/PR if I find a suitable fix that does not seem to cause breaking changes elsewhere in the API
Hi
I tried to use the library for creating new Manager-Client link.
I did it this way:
const googleAdsJs = new GoogleAdsApi({
client_id: 'xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
client_secret: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
developer_token: 'xxxxxxxxxxxxxxxxxxxx'
})
const manager = googleAdsJs.Customer({
customer_account_id: 'xxx-xxx-xxxx',
refresh_token: '1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
})
manager.customerClientLinks.create({
client_customer: 'customers/77777777777',
status: ManagerLinkStatus.PENDING
})
I've got error before call: TypeError: grpc[options.request] is not a constructor
I found couple possible typos in build/services/customer_client_link.js
:
const MUTATE_METHOD = 'mutateCustomerClientLinks';
const MUTATE_REQUEST = 'MutateCustomerClientLinksRequest';
and replace it with:
const MUTATE_METHOD = 'mutateCustomerClientLink';
const MUTATE_REQUEST = 'MutateCustomerClientLinkRequest';
This fix let me to go further and I got error in service.ts
:
TypeError: request.setOperationsList is not a function
at CustomerClientLinkService.<anonymous> (.../node_modules/google-ads-api/build/services/service.js:103:25)
Turned out CustomerClientLinkService doesn't have setOperationsList
method, but has setOperation
. I monkey-pathed that part as well and make call to API successfully.
if (!request.setOperationsList) {
request.setOperation(operations[0]);
}
else {
request.setOperationsList(operations);
}
I wish I fill PR with this patch, but I'm afraid I don't understand internal machinery of the library well and I'm not sure if my fix make sense for all cases.
Best,
Ilya
When using the refresh token helper I get this message "The redirect URI in the request, https://refresh-token-helper.opteo.com/callback/, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs,"
When deployed to Heroku (Linux), a server won't start because of this error. It looks like the filename wasn't updated from AdgroupCriterions
to AdGroupCriterions
but the references in Customer
were before 0.5.0 was released to npm. When I look in node_modules the file is still named AdgroupCriterions
. It seems like if the current version on Github is pushed to npm, that will fix the issue.
Documentation for The ConversionAction.attribution_model_settings.attribution_model
enums cite that each enum is sequential from 0 whereas in the the google ads api it uses different enum values for each attribution model.
Not actually a bug with the repo, the documentation just needs updating.
Since I'm not going to be accessing other users' accounts from my server (only one predefined account), the google api console suggested I should use a service account to authenticate.
Is there a way to use the service account json file downloaded from the credential UI with this library?
Thanks
We are having an issue creating a different type of ad (see #30): this time an image ad.
Using these params:
const b64 = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
const adId = await createAd({
ad_group: adGroup,
status: AdGroupAdStatus.PAUSED,
ad: {
name: "Image Ag",
final_urls: [ "https://my.url", ],
type: AdType.IMAGE_AD,
image_ad: {
image_url: "https://image.com/image.gif",
pixel_width: 600,
pixel_height: 600,
preview_image_url: "https://image.com/preview.gif",
preview_pixel_width: 600,
preview_pixel_height: 600,
name: "img.gif",
mime_type: MimeType.IMAGE_GIF,
data: b64
}
}
We get:
[ { wrappers_:
{ '1':
{ wrappers_:
{ '4':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 'customers/4674531019/adGroups/74761353488' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'5':
{ wrappers_:
{ '2':
[ { wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 'https://www.realestate.com.au/agent/lucas-harwood-1227455?rsf=cid:reach:lucasharwood:recentlysoldengage' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } ],
'22':
{ wrappers_:
{ '2':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array:
[ Uint8Array [
255,
216,
255,
224,
0,
16,
74,
70,
73,
70,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
255,
219,
0,
132,
0,
5,
3,
4,
13,
13,
14,
10,
13,
13,
13,
16,
13,
14,
10,
13,
13,
13,
13,
14,
13,
13,
10,
13,
14,
13,
8,
13,
8,
13,
8,
8,
8,
8,
8,
8,
13,
16,
13,
8,
8,
14,
13,
13,
8,
13,
21,
13,
14,
17,
17,
19,
19,
19,
8,
13,
22,
24,
22,
18,
24,
16,
18,
19,
18,
1,
5,
5,
5,
8,
7,
8,
15,
9,
9,
15,
... 14097 more items ] ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'4':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 600 ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'5':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 600 ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'6':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'7':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 600 ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'8':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 600 ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'9':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'11':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } },
messageId_: undefined,
arrayIndexOffset_: -1,
array:
[ <1 empty item>,
[ Uint8Array [
255,
216,
255,
224,
0,
16,
74,
70,
73,
70,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
255,
219,
0,
132,
0,
5,
3,
4,
13,
13,
14,
10,
13,
13,
13,
16,
13,
14,
10,
13,
13,
13,
13,
14,
13,
13,
10,
13,
14,
13,
8,
13,
8,
13,
8,
8,
8,
8,
8,
8,
13,
16,
13,
8,
8,
14,
13,
13,
8,
13,
21,
13,
14,
17,
17,
19,
19,
19,
8,
13,
22,
24,
22,
18,
24,
16,
18,
19,
18,
1,
5,
5,
5,
8,
7,
8,
15,
9,
9,
15,
... 14097 more items ] ],
<1 empty item>,
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
4,
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ] ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} },
'23':
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } },
messageId_: undefined,
arrayIndexOffset_: -1,
array:
[ <1 empty item>,
[ [ 'https://www.realestate.com.au/agent/lucas-harwood-1227455?rsf=cid:reach:lucasharwood:recentlysoldengage' ] ],
<2 empty items>,
14,
<4 empty items>,
[],
<5 empty items>,
[],
<5 empty items>,
[ <1 empty item>,
[ Uint8Array [
255,
216,
255,
224,
0,
16,
74,
70,
73,
70,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
255,
219,
0,
132,
0,
5,
3,
4,
13,
13,
14,
10,
13,
13,
13,
16,
13,
14,
10,
13,
13,
13,
13,
14,
13,
13,
10,
13,
14,
13,
8,
13,
8,
13,
8,
8,
8,
8,
8,
8,
13,
16,
13,
8,
8,
14,
13,
13,
8,
13,
21,
13,
14,
17,
17,
19,
19,
19,
8,
13,
22,
24,
22,
18,
24,
16,
18,
19,
18,
1,
5,
5,
5,
8,
7,
8,
15,
9,
9,
15,
... 14097 more items ] ],
<1 empty item>,
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
4,
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ] ],
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
<2 empty items>,
[] ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } },
messageId_: undefined,
arrayIndexOffset_: -1,
array:
[ <2 empty items>,
3,
[ 'customers/4674531019/adGroups/74761353488' ],
[ <1 empty item>,
[ [ 'https://www.realestate.com.au/agent/lucas-harwood-1227455?rsf=cid:reach:lucasharwood:recentlysoldengage' ] ],
<2 empty items>,
14,
<4 empty items>,
[],
<5 empty items>,
[],
<5 empty items>,
[ <1 empty item>,
[ Uint8Array [
255,
216,
255,
224,
0,
16,
74,
70,
73,
70,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
255,
219,
0,
132,
0,
5,
3,
4,
13,
13,
14,
10,
13,
13,
13,
16,
13,
14,
10,
13,
13,
13,
13,
14,
13,
13,
10,
13,
14,
13,
8,
13,
8,
13,
8,
8,
8,
8,
8,
8,
13,
16,
13,
8,
8,
14,
13,
13,
8,
13,
21,
13,
14,
17,
17,
19,
19,
19,
8,
13,
22,
24,
22,
18,
24,
16,
18,
19,
18,
1,
5,
5,
5,
8,
7,
8,
15,
9,
9,
15,
... 14097 more items ] ],
<1 empty item>,
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
4,
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ] ],
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
<2 empty items>,
[] ] ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } },
messageId_: undefined,
arrayIndexOffset_: -1,
array:
[ [ <2 empty items>,
3,
[ 'customers/4674531019/adGroups/74761353488' ],
[ <1 empty item>,
[ [ 'https://www.realestate.com.au/agent/lucas-harwood-1227455?rsf=cid:reach:lucasharwood:recentlysoldengage' ] ],
<2 empty items>,
14,
<4 empty items>,
[],
<5 empty items>,
[],
<5 empty items>,
[ <1 empty item>,
[ Uint8Array [
255,
216,
255,
224,
0,
16,
74,
70,
73,
70,
0,
1,
1,
0,
0,
1,
0,
1,
0,
0,
255,
219,
0,
132,
0,
5,
3,
4,
13,
13,
14,
10,
13,
13,
13,
16,
13,
14,
10,
13,
13,
13,
13,
14,
13,
13,
10,
13,
14,
13,
8,
13,
8,
13,
8,
8,
8,
8,
8,
8,
13,
16,
13,
8,
8,
14,
13,
13,
8,
13,
21,
13,
14,
17,
17,
19,
19,
19,
8,
13,
22,
24,
22,
18,
24,
16,
18,
19,
18,
1,
5,
5,
5,
8,
7,
8,
15,
9,
9,
15,
... 14097 more items ] ],
<1 empty item>,
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
[ 600 ],
[ 600 ],
[ 'https://s3-ap-southeast-2.amazonaws.com/agent-reach-content-generator-staging/240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
4,
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ] ],
[ '240751-d18f6aed478f069039ba73fe5933e2b6e2041977.png' ],
<2 empty items>,
[] ] ] ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } ]
The Mime Type field (id: 10) is missing.
Also: I'm not sure the best way to send that byte stream - as a decoded string?
Hey there
I'm having difficulty creating an Ad for my Ad Group, I did notice there was an issue where you would pass 2 enums into a create mutation - maybe somewhat related.
I'm using the latest package v1.2.2,
Below is the stack
// stack
ad params { ad_group: 'customers/4674531019/adGroups/74761353488',
status: 3,
ad:
{ final_urls: [ 'http://www.example.com' ],
type: 3,
name: 'best ad ever',
expanded_text_ad:
{ headline_part_1: 'Cruise to Mars #%d',
headline_part_2: 'Best Space Cruise Line',
description: 'Buy your tickets now!',
path_1: 'all-inclusive',
path_2: 'deals' } } }
{ Error: The required field was not present in the resource.
at AdGroupAdService.<anonymous> (/Users/matt/rea/rea-google-campaigns/node_modules/google-ads-api/build/services/service.js:142:23)
at Generator.throw (<anonymous>)
at rejected (/Users/matt/rea/rea-google-campaigns/node_modules/google-ads-api/build/services/service.js:5:65)
at <anonymous>
code:
{ requestError: 0,
biddingStrategyError: 0,
urlFieldError: 0,
listOperationError: 0,
queryError: 0,
mutateError: 0,
fieldMaskError: 0,
authorizationError: 0,
internalError: 0,
quotaError: 0,
adError: 0,
adGroupError: 0,
campaignBudgetError: 0,
campaignError: 0,
authenticationError: 0,
adGroupCriterionError: 0,
adCustomizerError: 0,
adGroupAdError: 0,
adSharingError: 0,
adxError: 0,
assetError: 0,
biddingError: 0,
campaignCriterionError: 0,
collectionSizeError: 0,
countryCodeError: 0,
criterionError: 0,
customerError: 0,
dateError: 0,
dateRangeError: 0,
distinctError: 0,
feedAttributeReferenceError: 0,
functionError: 0,
functionParsingError: 0,
idError: 0,
imageError: 0,
languageCodeError: 0,
mediaBundleError: 0,
mediaFileError: 0,
multiplierError: 0,
newResourceCreationError: 0,
notEmptyError: 0,
nullError: 0,
operatorError: 0,
rangeError: 0,
recommendationError: 0,
regionCodeError: 0,
settingError: 0,
stringFormatError: 0,
stringLengthError: 0,
operationAccessDeniedError: 0,
resourceAccessDeniedError: 0,
resourceCountLimitExceededError: 0,
adGroupBidModifierError: 0,
contextError: 0,
fieldError: 2,
sharedSetError: 0,
sharedCriterionError: 0,
campaignSharedSetError: 0,
conversionActionError: 0,
conversionAdjustmentUploadError: 0,
conversionUploadError: 0,
headerError: 0,
databaseError: 0,
policyFindingError: 0,
enumError: 0,
keywordPlanError: 0,
keywordPlanCampaignError: 0,
keywordPlanNegativeKeywordError: 0,
keywordPlanAdGroupError: 0,
keywordPlanKeywordError: 0,
keywordPlanIdeaError: 0,
accountBudgetProposalError: 0,
userListError: 0,
changeStatusError: 0,
feedError: 0,
geoTargetConstantSuggestionError: 0,
feedItemError: 0,
labelError: 0,
billingSetupError: 0,
customerClientLinkError: 0,
customerManagerLinkError: 0,
feedMappingError: 0,
customerFeedError: 0,
adGroupFeedError: 0,
campaignFeedError: 0,
customInterestError: 0,
extensionFeedItemError: 0,
adParameterError: 0,
feedItemValidationError: 0,
extensionSettingError: 0,
feedItemTargetError: 0,
policyViolationError: 0,
mutateJobError: 0,
partialFailureError: 0,
policyValidationParameterError: 0 },
request:
{ customerId: '4674531019',
operationsList: [ [Object] ],
partialFailure: false,
validateOnly: false },
request_id: '_8Ph9A0hYxiAur6tzn6Qqw',
failure:
{ Error: 3 INVALID_ARGUMENT: The required field was not present in the resource.
at Object.exports.createStatusError (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/common.js:91:15)
at Object.onReceiveStatus (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:1204:28)
at InterceptingListener._callNext (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:618:8)
at Object.grpc_1.default.ListenerBuilder.withOnReceiveStatus [as onReceiveStatus] (/Users/matt/rea/rea-google-campaigns/node_modules/google-ads-node/build/lib/interceptor.js:68:17)
at InterceptingListener._callNext (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:618:8)
at Object.grpc_1.default.ListenerBuilder.withOnReceiveStatus [as onReceiveStatus] (/Users/matt/rea/rea-google-campaigns/node_modules/google-ads-node/build/lib/interceptor.js:151:13)
at InterceptingListener._callNext (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/Users/matt/rea/rea-google-campaigns/node_modules/grpc/src/client_interceptors.js:618:8)
code: 3,
metadata: Metadata { _internal_repr: [Object] },
details: 'The required field was not present in the resource.' } }
Here is my code which creates an Ad,
// service
export const createAd = async (ad: types.AdGroupAd) => {
const response = await customer.adGroupAds.create(ad);
return response.results;
};
// builder
import { createAd } from "../services/googleService";
import { types } from "google-ads-api";
import { AdGroupAdStatus, AdType } from "google-ads-node/build/lib/enums";
export const buildParamsForAd = adGroup => {
/*eslint-disable @typescript-eslint/camelcase*/
const ad: types.AdGroupAd = {
ad_group: adGroup,
status: AdGroupAdStatus.PAUSED,
ad: {
final_urls: ['http://www.example.com'],
type: AdType.EXPANDED_TEXT_AD,
name: 'best ad ever',
expanded_text_ad: {
headline_part_1: 'Cruise to Mars #%d',
headline_part_2: 'Best Space Cruise Line',
description: 'Buy your tickets now!',
path_1: 'all-inclusive',
path_2: 'deals'
}
},
};
return ad;
};
export const createGoogleAd = async adParams => {
const adId = await createAd(adParams);
return adId;
};
// cli
import minimist from "minimist";
import { buildParamsForAd, createGoogleAd } from "../ad/createAd";
// Example
// $ node dist/cli/createAdCli.js --adGroup "customers/4674531019/adGroups/74761353488"
const params = minimist(process.argv);
const adGroup: string = params["adGroup"];
const adParams = buildParamsForAd(adGroup);
console.log("ad params", adParams);
createGoogleAd(adParams)
.then(data => console.log("ad:", data))
.catch(err => console.log(err));
Not sure what argument is Invalid? Am I missing something here?
Help would be much appreciated,
Thanks :)
I can't seem to add comments to #43 - not sure if it's because of the way you guys set up workflow on issues or if something is b0rked on my end... Would appreciate if someone could check into that and reply here, and otherwise try to resume the conversation for #43 on the thread for #43 :)
In any case, I wanted to say there that it happens for a query that is returning (or trying to return) 9MB of data
For me it was enough to run a 30 day report on a busy account with lots of ads, and asking for lots of user-presentable strings, like the ad text, search keywords, search terms, and account/campaign/adgroup names (but YMMV based on your account activity.)
Regarding a solution, I'm far from a gRPC maven, but I've been seeing lots about a stream interface which allows a response (or request) to be split into several payloads...
Would this be relevant? https://grpc.github.io/grpc/node/grpc-ClientReadableStream.html
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.