Posts under category Google

Problem: I have an appointment booking widget (non-iframe) embeded into a webpage. How do I ensure GA4 is picking up on these form submissions?

Additionally, how does the form submission correlate up to the success of the Google Ad?

I have embeded this javascript in the form to ensure it fires data to GA4, but marketers are still telling me the conversions are not appearing with a traffic source from the UTM.


async function triggerConversionEvent() {

        const measurementId = 'measurementId'; // Replace with your GA4 Measurement ID         const conversionEventName = 'self_booked_appointment'; // Replace with your conversion event name         const clientId = 'booking_engine'; // Replace with a unique client ID (can be randomly generated)         const url = `https://www.google-analytics.com/mp/collect?measurement_id=${measurementId}`;         const body = {             client_id: clientId,             events: [                 {                     name: 'conversion',                     params: {                         event_name: conversionEventName,                     }                 }             ]         };         try {             const response = await fetch(url, {                 method: 'POST',                 headers: {                     'Content-Type': 'application/json'                 },                 body: JSON.stringify(body)             });             if (response.ok) {                 console.log('Conversion event triggered successfully');             } else {                 console.error('Failed to trigger conversion event');             }         } catch (error) {             console.error('Error triggering conversion event:', error);         }     } 

I have implemented server-side tagging in in Google Tag Manager (GTM), but I'm sending HTTP requests directly from my backend code, rather than using JavaScript on the frontend (as many other developers). Since, the conversion tracking cookies set by Meta and Google aren't automatically sent when sending a HTTP request from my backend code, I am getting the _fbp and _fbc cookie values from the context and sending them as a "ep.x-fb-ck-fbp" and "ep.x-fb-ck-fbc" to the GTM server container, which allows me to track Facebook ads conversions successfully.

I am now looking to replicate this process for Google Ads. I understand that for Google Ads conversion tracking, the GCLID is a parameter that sets the _gcl_aw cookie which I should use to track conversion. However, I am not certain how to send this cookie value in the Http request that I'm sending from my server to the GTM server container.

In other words, if I'm sending the Meta's _fbc cookie value as a "ep.x-fb-ck-fbc" parameter, how should I send the Google's _gcl_aw and _gcl_au cookies.

var adRequested by remember { mutableStateOf(false) } if (AdEventManager.isInternetAvailable() && !adRequested &&          isNativeAdVisible && !App.isAppPremium) {     AndroidViewBinding(         NativeNoMediaCLayoutBinding::inflate,         modifier = Modifier             .fillMaxWidth()             .weight(1f)             .navigationBarsPadding()     ) {         App.mInstance?.adsManager?.loadNativeAd(             context as Activity,             adFrame,             AdsManager.NativeAdType.NOMEDIA_MEDIUM,             context.getString(R.string.ADMOB_NATIVE_WITHOUT_MEDIA_V2),                               shimmerLayout)     }     adRequested = true } 

so here i want that when the ad is Loaded once then it should not be loaded again and again whenever the screen is recomposed so we go with a state that tracks that if the ad is loaded or not but the issue we have here is that even we cant make a side effect that will run this block only when its true.As by this code request is sent one time but when the screen recompose the ad is hidden as we have that in the if statement So how to make sure that the ad is loaded once and if was loaded then that View should remain same and don't reload

This is my Ad provider

import 'package:bg_remover/services/ads_helper.dart'; import 'package:flutter/material.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; class AdaptiveBannerAdProvider with ChangeNotifier{   BannerAd? _anchoredAdaptiveAd;   bool _isLoaded = false;   BannerAd? get anchoredAdaptiveAd => _anchoredAdaptiveAd;   bool get isAdLoaded => _isLoaded;   Future<void> loadAnchoredAdaptiveAd(BuildContext context) async {     final AnchoredAdaptiveBannerAdSize? size =         await AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(             MediaQuery.of(context).size.width.truncate());     if (size == null) {       debugPrint('Unable to get height of anchored banner.');       return;     }     _anchoredAdaptiveAd = BannerAd(       adUnitId: AdHelper.bannerAdUnitId,       size: size,       request: const AdRequest(),       listener: BannerAdListener(         onAdLoaded: (Ad ad) {           debugPrint('$ad has been >>>>>loaded: ${ad.responseInfo}');           //there was an error of @This AdWidget is already in the Widget tree@           // so for that we apply this widgetsBinding to notify listener           //and place the banner add in FutureBuilder and that's work           // WidgetsBinding.instance.addPostFrameCallback((_) {           //   _isLoaded = true;           //   notifyListeners();           // });           // Ad was not showing when loaded           _isLoaded = true;           notifyListeners();         },         onAdFailedToLoad: (Ad ad, LoadAdError error) {           debugPrint('Anchored adaptive banner failedToLoad: $error');           ad.dispose();         },       ),     );     return _anchoredAdaptiveAd!.load();   }   void disposeAd() {     _anchoredAdaptiveAd?.dispose();   } } 

call it here to display Ad:

 import 'package:bg_remover/utils/routes/routes_name.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:gap/gap.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:provider/provider.dart'; import '../provider/ads_provider/adaptiveBanner_ad_provider.dart'; import '../utils/colors.dart'; import '../utils/images_assets_path.dart'; import '../utils/strings.dart'; import 'bottom_tabs/home_page.dart'; import 'bottom_tabs/project_page.dart'; import 'bottom_tabs/settings_page.dart'; class HomeFeedPage extends StatefulWidget{   const HomeFeedPage({Key? key}) : super(key: key);   @override   State<HomeFeedPage> createState() => _HomeFeedPageState(); } class _HomeFeedPageState extends State<HomeFeedPage>{   int index = 1;   final List<Widget> pages = const [     ProjectPage(),     HomePage(),     SettingsPage(),   ];   final List<String> icons = [     AssetImages.projectIcon,     AssetImages.inactiveHomeIcon,     AssetImages.settingsIcon,   ];   final List<String> titles = const [     Strings.projects,     Strings.home,     Strings.settings,   ];   void _onIconPressed(int newIndex) {     if (newIndex == 2) {       Navigator.pushNamed(context, RoutesName.settings);     } else {       setState(() {         index = newIndex;       });     }   }   @override   void didChangeDependencies() {     super.didChangeDependencies();     final adaptiveAdProvider =         Provider.of<AdaptiveBannerAdProvider>(context, listen: false);     adaptiveAdProvider.loadAnchoredAdaptiveAd(context);   }   @override   Widget build(BuildContext context) {     return Scaffold(       resizeToAvoidBottomInset: false,       body: Column(         children: [           Expanded(child: pages[index]),           displayAd(),           _buildBottomBar(),         ],       ),     );   }   Widget _buildBottomBar() {     return Container(       padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),       color: AppColors.bottomBarColor,       child: Row(         mainAxisAlignment: MainAxisAlignment.spaceAround,         children: List.generate(           icons.length,           (int i) => GestureDetector(             onTap: () => _onIconPressed(i),             child: _buildIconColumn(i),           ),         ),       ),     );   }   Widget _buildIconColumn(int i) {     final bool isActiveHome = index == 1 && i == 1;     final String iconPath = isActiveHome ? AssetImages.homeIcon : icons[i];     return Column(       children: [         AnimatedContainer(           duration: const Duration(milliseconds: 300),           width: 70,           height: 35,           decoration: BoxDecoration(             color: index == i ? AppColors.activeTabColor : Colors.transparent,             borderRadius: BorderRadius.circular(20),           ),           child: Padding(             padding: const EdgeInsets.all(8.0),             child: SvgPicture.asset(               iconPath,               colorFilter: ColorFilter.mode(                 index == i ? AppColors.whiteColor : AppColors.activeColor,                 BlendMode.srcIn,               ),             ),           ),         ),         const Gap(5),         Text(           titles[i],           style: TextStyle(             color: index == i ? AppColors.whiteColor : AppColors.activeColor,             fontWeight: index == i ? FontWeight.w700 : null,           ),         ),       ],     );   }   Widget displayAd() {     return Consumer<AdaptiveBannerAdProvider>(       builder: (context, adProvider, _) {         if (adProvider.isAdLoaded) {           return SizedBox(             width: adProvider.anchoredAdaptiveAd!.size.width.toDouble(),             height: adProvider.anchoredAdaptiveAd!.size.height.toDouble(),             child: AdWidget(ad: adProvider.anchoredAdaptiveAd!),           );         } else {           return Container(             color: AppColors.yellowColor,             width: adProvider.anchoredAdaptiveAd?.size.width.toDouble(),             height: adProvider.anchoredAdaptiveAd?.size.height.toDouble(),             child: Center(               child: Text(                 'Ad is Loading.......',                 style: TextStyle(color: AppColors.whiteColor),               ),             ),           );         }       },     );   }  verride   void dispose() {     Provider.of<AdaptiveBannerAdProvider>(context, listen: false).disposeAd();     super.dispose();   } }  @ 

working fine when I go to next having same process to display ad show error : Flutter :- This AdWidget is already in the Widget tree. How to disable this exception. And what does it mean?

Above Code is Working fine on HomeFeed Page. when I go to next having same process to display ad error : Flutter :- This AdWidget is already in the Widget tree. How to disable this exception. And what does it mean?

I'm using the Google Ads REST API to retrieve a list of customers and display them to the user. I want to display these customers alongside metadata like the account name, whether it's a manager account or not, etc.

I've already got a list of accessible customers using https://googleads.googleapis.com/v15/customers:listAccessibleCustomers. However, I can't find the appropriate documentation for retrieving the customer object itself using the customer id.

I've tried using the https://googleads.googleapis.com/v15/customers/{customerID}/operations/get endpoint, however this always returns a 404 resource not found error.

Any help would be appreciated. Thank you.