Posts under category google-ads-api

I am trying to add google native ads in my flutter app using this library

https://pub.dev/packages/google_mobile_ads

i am getting this error:

\[log\] NativeAd failed to load: LoadAdError(code: 0, domain: com.google.android.gms.ads, message: Internal error., responseInfo: ResponseInfo(responseId: _-SvZbabD5e-3LUP4oaxkAs, mediationAdapterClassName: , adapterResponses: \[AdapterResponseInfo(adapterClassName: com.google.ads.mediation.admob.AdMobAdapter, latencyMillis: 83, description: { "Adapter": "com.google.ads.mediation.admob.AdMobAdapter", "Latency": 83, "Ad Source Name": "Reservation campaign", "Ad Source ID": "7068401028668408324", "Ad Source Instance Name": "\[DevRel\] \[DO NOT EDIT\] Native Ads Campaign", "Ad Source Instance ID": "3518433842871043", "Credentials": { "pubid": "ca-app-pub-3940256099942544/2247696110/cak=no_cache&cadc=c3&caqid=_-SvZfiWDr-FmsMPtMWtgAM", "campaign_id": "12584073087" }, "Ad Error": { "Code": 0, "Message": "Internal error.", "Domain": "com.google.android.gms.ads", "Cause": "null" } }, adUnitMapping: {pubid: ca-app-pub-3940256099942544/2247696110/cak=no_cache&cadc=c3&caqid=\_-SvZfiWDr-FmsMPtMWtgAM, campaign_id: 12584073087}, adError: AdError(code: 0, domain: com.google.android.gms.ads, message: Internal error.), adSourceName: Reservation campaign, adSourceId: 7068401028668408324, adSourceInstanceName: \[DevRel\] \[DO NOT EDIT\] Native Ads Campaign, adSourceInstanceId: 3518433842871043)\], loadedAdapterResponseInfo: null), responseExtras: {mediation_group_name: Campaign}) 

Minimal Code to Reproduce

Native Controller:

import 'package:get/get.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; class NativeAdController extends GetxController{   NativeAd? ad;   final adLoaded = false.obs; } 

Ad Helper:

import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import '../controllers/controller_native_ads.dart'; class AdHelper{   static Future<void> initAds() async {     await MobileAds.instance.initialize();   }   void loadInterstitialAd({required VoidCallback onComplete}) {     InterstitialAd.load(       adUnitId: 'ca-app-pub-3940256099942544/1033173712',       request: const AdRequest(),       adLoadCallback: InterstitialAdLoadCallback(         // Called when an ad is successfully received.         onAdLoaded: (ad) {           ad.fullScreenContentCallback = FullScreenContentCallback(             onAdDismissedFullScreenContent: (ad) {               onComplete();             },             onAdFailedToShowFullScreenContent: (ad, error) {               log(error.toString());             },             onAdShowedFullScreenContent: (ad) {               log("Full Screen");             },           );           log('This is the $ad loaded.');         },         // Called when an ad request failed.         onAdFailedToLoad: (LoadAdError error) {           log('InterstitialAd failed to load: $error');         },       ),     );   }   static NativeAd loadNativeAd({required NativeAdController nativeAdController}) {     return NativeAd(       adUnitId: 'ca-app-pub-3940256099942544/2247696110',       listener: NativeAdListener(         onAdLoaded: (ad) {           log('$NativeAd loaded.');           nativeAdController.adLoaded.value = true;         },         onAdFailedToLoad: (ad, error) {           log('$NativeAd failed to load: $error');           ad.dispose();         },       ),       request: const AdRequest(),       // Styling       nativeTemplateStyle: NativeTemplateStyle(         templateType: TemplateType.small,       ),     )..load();   } } 

Test Screen:

import 'package:flutter/material.dart'; import '../controllers/controller_native_ads.dart'; class TestScreen extends StatelessWidget{   TestScreen({super.key});   final adController = Get.put(NativeAdController());   @override   Widget build(BuildContext context) {     adController.ad = AdHelper.loadNativeAd(nativeAdController: adController);     return Scaffold(       bottomNavigationBar: adController.ad != null && adController.adLoaded.isTrue           ? SafeArea(               child: SizedBox(                 height: 80,                 child: AdWidget(ad: adController.ad!),               ),             )           : null,     );   } } 

I am using test id provided by official google docs flutter-quick-start

Can anyone explain me why this error occurs?

I have successfully uploaded the video to my channel with YouTube API and used this video as an ad asset.

but,I hope to upload video materials to Ad Storage Channel

I tried to specify the ChannelID when uploading the video, but it did not work It uploads the video to my Youtube channel

enter image description here

Is there any way to upload the video to this channel?

I've tried with this documentation authenticate and with this REST to send the conversion over REST API due to missing Typescript/Javascript-Client-Bib.

I am already failing at the authentication. I hope, if the authentication is working, the click conversion will be send. For the case I am guessing wrong, I extended the question. I hope the question is not to big. Blame me if I am wrong.

This is my error:

My setup Regarding to the documentation I have a google ads account with a developer token. This token will be used, when I send the click conversion, as you can see here. The token has nothing to do with the authentication of the service account. Therefore I have a service account on the Google Cloud Project, which also has the Google Ads Api enabled.

I also added to the workspace domain to the domain wide delegation the client id of the service account with the scope https://www.googleapis.com/auth/adwords This created in the category APIs & Services also an OAuth 2.0 Client IDs The clientIds are fitting as well.

Just in case I also added an OAuth consent screen with the scope https://www.googleapis.com/auth/adwords with the Testing status and external. But I don't think I will need this with a service account.

The service account itself has no further related rights. The documentation don't give me the info, that the service account need further rights. My thoughts: I added the client id to the domain wide delegation, this should be enough. I hope I am wrong here.

Now everything should be set up. I hope I didn't miss a step.

My guess: Either I am missing some rights. Or I missunderstand the refresh token in the function authenticateToGoogleAdsManager. I create a signed JWT. Google says here, I need a refresh token. But the authentication via await fetch('https://oauth2.googleapis.com/token' just gives me an access token. So I thought I just need a jwt here.

This is the way I am executing my code (in a testcase. Service Account JSON and clickConversion are given.)

 // First I create a signed jwt     const jwt = generateJsonWebTokenForServiceAccount(       serviceAccount,       ['https://www.googleapis.com/auth/adwords'],       'googleads'     )     // Then I use the signed jwt to authenticate to Google Ads Manager     const authenticationResult = await authenticateToGoogleAdsManager(       serviceAccount.client_id,       serviceAccount.private_key,       jwt     )     console.log(authenticationResult)     // Then I use the access token to send a click conversion to Google Ads Manager     const test = await sendClickConversionToGoogleAdsManager(       CUSTOMERID,       clickConversion,       accessToken.access_token,       'DEV-TOKEN'     ) 

Here are my functions:

/**  * Generates a JSON Web Token (JWT) for a service account.  *  * @param serviceAccount - The service account object containing the client email and private key.  * @param scopes - An array of scopes for which the token will be authorized.  * @param serviceName - The name of the service for which the token will be authorized. Default is 'oauth2'.  * @param expirationTimeInSeconds - The expiration time of the token in seconds. Default is 3600 seconds (1 hour).  * @returns The generated JSON Web Token.  */ export function generateJsonWebTokenForServiceAccount(serviceAccount: ServiceAccount,   scopes: string[],   serviceName: string = 'oauth2',   expirationTimeInSeconds = 3600) {   const aud =     serviceName === 'oauth2' ? 'https://oauth2.googleapis.com/token' : `https://${serviceName}.googleapis.com/`   const currentTimestamp = Math.floor(Date.now() / 1000)   const expirationTimestamp = currentTimestamp + expirationTimeInSeconds   const payload = {     iss: serviceAccount.client_email,     sub: serviceAccount.client_email,     scope: scopes.join(' '),     aud: aud,     exp: expirationTimestamp,     iat: currentTimestamp   }   const options: SignOptions = {     algorithm: 'RS256'   }   return jwt.sign(payload, serviceAccount.private_key, options) } /**  * Authenticates to Google Ads Manager using the provided credentials.  * @param clientId The client ID for authentication.  * @param clientSecret The client secret for authentication.  * @param refreshToken The refresh token for authentication.  * @returns A promise that resolves to the access token.  */ export async function authenticateToGoogleAdsManager(clientId: string,   clientSecret: string,   refreshToken: string): Promise<string> {   const url = 'https://www.googleapis.com/oauth2/v3/token'   const body = {     client_id: clientId,     client_secret: clientSecret,     refresh_token: refreshToken,     grant_type: 'refresh_token'   }   const response = await fetch(url, {     method: 'POST',     body: JSON.stringify(body)   })   const data = await response.json()   return data.access_token } /**  * Sends a click conversion to Google Ads Manager.  *   * @param customerId - The ID of the customer.  * @param clickConversion - The click conversion data.  * @param accessToken - The access token for authentication.  * @param developerToken - The developer token for authentication.  * @param options - Optional API options.  * @returns A promise that resolves to void.  */ export async function sendClickConversionToGoogleAdsManager(customerId: number,   clickConversion: ClickConversion,   accessToken: string,   developerToken: string,   options?: ApiOptions): Promise<void> {   const url = `https://googleads.googleapis.com/v15/customers/${customerId}:uploadClickConversions`   if (!options) {     options = {       partialFailure: false,       validateOnly: false,       debugEnabled: false,       jobId: 0     }   }   const response = await fetch(url, {     method: 'POST',     headers: {       'Content-Type': 'application/json',       Authorization: `Bearer ${accessToken}`,       'developer-token': developerToken     },     body: JSON.stringify({       conversions: [clickConversion],       partialFailure: options.partialFailure,       validateOnly: options.validateOnly,       debugEnabled: options.debugEnabled,       jobId: options.jobId     })   })   const data = await response.json()   return data } 

I am using this script based on the documentation: https://developers.google.com/google-ads/api/samples/add-image-extension

def create_image_extensions(df):     for index,row in df.iterrows():         extension_feed_item_service =              client.get_service("ExtensionFeedItemService")         extension_feed_item_operation =              client.get_type("ExtensionFeedItemOperation")         extension_feed_item = extension_feed_item_operation.create         extension_feed_item.image_feed_item.image_asset =               client.get_service("AssetService").asset_path(account_id,                  row.asset_id)         response = extension_feed_item_service.mutate_extension_feed_items(customer_id=account_id, operations=\[extension_feed_item_operation\])         image_resource_name = response.results\[0\].resource_name         print("Created an image extension with resource name: "f"'{image_resource_name}'")             campaign_extension_setting_service = client.get_service("CampaignExtensionSettingService")         campaign_extension_setting_operation = client.get_type("CampaignExtensionSettingOperation")         ces = campaign_extension_setting_operation.create         ces.campaign = client.get_service("CampaignService").campaign_path(account_id, row.campaign_id)         ces.extension_type = client.enums.ExtensionTypeEnum.IMAGE         ces.extension_feed_items.append(image_resource_name)              response = (             campaign_extension_setting_service.mutate_campaign_extension_settings(                 customer_id=account_id,                 operations=[campaign_extension_setting_operation],             )         )         print("Created a campaign extension setting with resource name: "f"'{response.results[0].resource_name}'")` 

But running into an error now:

Method: /google.ads.googleads.v15.services.ExtensionFeedItemService/MutateExtensionFeedItems, RequestId: B5OFT8TdalKrrmx0lEdMkA, IsFault: True, FaultMessage: Feed-based extension is read-only for this extension type. error_code {     feed_error: LEGACY_EXTENSION_TYPE_READ_ONLY   }   message: "Feed-based extension is read-only for this extension type." 

I am getting this error and my code is below

 - (void)viewWillAppear:(BOOL)animated {       NSLog(@"self.inter eve reload cl %@", self.interstitial);       DebugAssert(index != NSNotFound);       double delayInSeconds = 5.0;       dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));            if (!didPurchaseAds) {                 dispatch_after(popTime, dispatch_get_main_queue(), ^(void){                 NSLog(@"Interstitial ad loaded %ld", (long)index);                     if ((index % 2 == 0)) {                          NSLog(@"Interstitial ad loaded for even num %ld", (long)index);                             if (self.interstitial) {                                 NSLog(@"Show InterstitialAd %@", self.interstitial);                                 [self.interstitial presentFromRootViewController:self];                                 [self.interstitial presentFromRootViewController:self];                               } else {                                 NSLog(@"Ad wasn't ready event");                            }                         }                   });           }     }          - (void)viewDidLoad{        [super viewDidLoad];         [self loadInterstitial];     }          - (void)loadInterstitial {             GADRequest *request = [GADRequest request];             [GADInterstitialAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910"                                         request:request                               completionHandler:^(GADInterstitialAd *ad, NSError *error) {                 if (error) {                     NSLog(@"Failed to load interstitial ad with error: %@", [error localizedDescription]);                     return;                 }                 self.interstitial = ad;                 self.interstitial.fullScreenContentDelegate = self;             }];         }               - (void)ad:(nonnull id<GADFullScreenPresentingAd>)ad     didFailToPresentFullScreenContentWithError:(nonnull NSError *)error {         NSLog(@"Ad did fail to present full screen content.");     }          /// Tells the delegate that the ad will present full screen content.     - (void)adWillPresentFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad {         NSLog(@"Ad will present full screen content.");     }          /// Tells the delegate that the ad dismissed full screen content.     - (void)adDidDismissFullScreenContent:(nonnull id<GADFullScreenPresentingAd>)ad {        NSLog(@"Ad did dismiss full screen content.");     }