So laden Sie Rohdaten von Google Ads in Google BigQuery hoch

Veröffentlicht: 2022-04-12

Durch die Analyse der Effektivität von Google Ads-Werbekampagnen in Google Analytics können Stichproben, Datenaggregation oder andere Einschränkungen der Systemschnittstelle auftreten. Glücklicherweise lässt sich dieses Problem leicht lösen, indem Sie Rohdaten von Ihrem Werbedienst zu Google BigQuery hochladen.

In diesem Artikel erfahren Sie, wie Sie Rohdaten aus Ihrem Google Ads-Konto in BigQuery hochladen und alle UTM-Tags für Kampagnen mit automatischem Label identifizieren.

Sie benötigen OWOX BI, um Kampagneninformationen mit Benutzeraktivitäten auf der Website zu verknüpfen. Melden Sie sich für eine Demo an und wir zeigen Ihnen alle Herausforderungen, die Sie mit OWOX BI lösen können.

MELDEN SIE SICH FÜR EINE DEMO AN

Inhaltsverzeichnis

  • Warum Sie Rohdaten von Google Ads benötigen
  • Zwei Möglichkeiten zum Hochladen von Rohdaten aus Google Ads in BigQuery
  • So konfigurieren Sie den Upload mithilfe von Data Transfer
  • So richten Sie den Upload mit Ads Script ein
  • So verbinden Sie den Datendownload von Google Ads mit OWOX BI
  • Nützliche Tipps

Finden Sie den wahren Wert von Kampagnen heraus

Importieren Sie automatisch Kostendaten aus all Ihren Werbediensten in Google Analytics. Vergleichen Sie Kampagnenkosten, CPC und ROAS in einem einzigen Bericht.

Testversion starten

Warum Sie Rohdaten von Google Ads benötigen

Rohdaten von Google Ads ermöglichen Ihnen eine Keyword-genaue Analyse von Werbekampagnen. Durch das Hochladen von Daten in BigQuery können Sie:

  • Erstellen Sie Berichte so detailliert wie Sie möchten, ohne durch GA-Einschränkungen eingeschränkt zu sein.
  • Bestimmen Sie die Effektivität von Werbekampagnen auf Sitzungs- und Benutzerebene.
  • Berechnen Sie ROI, ROAS, CRR nach Region, Benutzertyp (neu oder zurückgekehrt), Gerät und anderen Parametern.
  • Verwalten Sie Ihre Tarife effektiv und erstellen Sie Remarketing-Listen.
  • Kombinieren Sie Daten aus Google Ads, Google Analytics und CRM, um die Effektivität von Kampagnen basierend auf der Marge und Einlösbarkeit Ihrer Artikel zu bewerten.
  • Trainieren Sie Ihr ML-Modell für eine genauere Planung.

Um zu verstehen, welche Kampagnen, Anzeigen und Keywords Nutzer auf Ihre Website bringen, müssen Sie Daten aus Google Ads und Analytics in BigQuery kombinieren. Sie können dies mit dem OWOX BI-Streaming tun.

Durch das Streaming dieser Informationen werden ungesampelte Daten zum Benutzerverhalten auf Ihrer Website an GBQ gesendet. Treffer werden in Echtzeit übertragen, dann werden basierend auf diesen Treffern Sitzungen gebildet.

TESTEN SIE OWOX BI KOSTENLOS

OWOX BI-Verkehrsquelleninformationen werden aus dem Werbe-Markup von UTM-Tags entnommen. Tags sind manuell und automatisch.

Angenommen, Sie haben die Anzeige manuell markiert und diese URL erhalten:

https://example.com/?utm_source=facebook&utm_medium=cpc&utm_campaign=utm_tags

In diesem Fall stehen Ihnen nach der Verbindung mit OWOX BI Quell-, Kanal- und Kampagnendaten in der GBQ-Tabelle zur Verfügung:

  • trafficSource.source — google
  • trafficSource.medium — cpc
  • trafficSource.campaign — utm_tags

Lesen Sie mehr darüber, wie Sie UTM-Tags korrekt erstellen.

Wenn Sie das automatische Markup im Werbedienst aktiviert haben, wird jeder Ihrer Anzeigen ein spezieller gclid-Parameter zugewiesen. Sie wird der Zielseiten-URL hinzugefügt, wenn der Benutzer auf die Ankündigung klickt.

Beispiel für einen solchen Link:

http://www.example.com/?gclid=TeSter-123

Wenn Sie ein automatisches Markup verwenden, können Sie Quelle, Medium oder Kampagne nicht ohne Rohdaten von gclid abrufen – diese Felder sind in den von OWOX BI erfassten BigQuery-Tabellen leer.

Was können Sie in einem solchen Fall tun und wie können Sie den Namen von Kampagnen und anderen Parametern erhalten, wenn Sie nur die gclid haben? Konfigurieren Sie den automatischen Upload von Google Ads zu GBQ.

Hinweis: Wenn die Ankündigung überhaupt nicht markiert ist, weist OWOX BI den Link wie folgt zu:

  • für Nicht-Google-Quellen als Referral-Traffic (z. B. Facebook/Referral)
  • für Google-Quelle als direkter Traffic (direkt/keine)

Wenn in Ihren Berichten viel direkter/kein Traffic vorhanden ist, haben Sie möglicherweise keine Bot-Filterung aktiviert oder Sie haben möglicherweise eine große Anzahl von Anzeigen ohne Tags.

Zwei Möglichkeiten zum Hochladen von Rohdaten aus Google Ads in BigQuery

Wir verwenden und empfehlen zwei Methoden zum Hochladen von Rohdaten aus Google Ads: Data Transfer Connector und Ads Script.

Welchen Weg Sie wählen, hängt von Ihren Zielen und Ihrem Budget ab.

Datenübertragungsfunktionen

  • Native Integration mit GBQ.
  • Laden Sie historische Daten für einen beliebigen Zeitraum ohne Einschränkungen herunter.
  • Kostenlos.

Google Ads Script-Funktionen

  • Frei.
  • Sie können keine historischen Daten hochladen. Es werden nur die Informationen des Vortages heruntergeladen.
  • Erfordert mehr, wenn Sie den Upload von einer großen Anzahl von Konten einrichten möchten. Sie müssen Skriptänderungen für jedes Konto manuell vornehmen. Gleichzeitig besteht ein hohes Risiko, einen Fehler zu machen.

Was Sie für Einstellungen benötigen

Aktive Projekte und Accounts in:

  • Google Cloud-Plattform (GCP)
  • Google BigQuery (GBQ)
  • OWOX BI
  • Google Ads

Zugriff:

  • Eigentümer in der GCP
  • Administrator in GBQ
  • Bearbeitung in OWOX BI. Wichtig: Nur der Nutzer, der die Google Analytics → Google BigQuery-Streaming-Pipeline erstellt hat, kann das Herunterladen von Google Ads aktivieren.
  • Lesen in Google Ads

So erteilen Sie Zugriffsrechte in GBQ

Öffnen Sie die GCP-Konsole und wählen Sie im seitlichen Menü IAM und Admin – Ressource verwalten aus. Wählen Sie dann das Projekt aus und klicken Sie auf Mitglied hinzufügen. Geben Sie die E-Mail-Adresse des Benutzers ein, wählen Sie die BigQuery-Administratorrolle aus und speichern Sie Ihre Änderungen.

BigQuery-Zugriff

So konfigurieren Sie den Upload mithilfe von Data Transfer

Schritt 1. Erstellen Sie ein Projekt in der Google Cloud Platform

Wenn Sie bereits ein Projekt in GCP haben, überspringen Sie diesen Schritt. Wenn nicht, öffnen Sie die GCP-Konsole und wählen Sie IAM und Admin – Ressource verwalten aus dem Seitenmenü aus. Klicken Sie auf die Schaltfläche Projekt erstellen. Geben Sie dann den Projektnamen ein, geben Sie die Organisation an und klicken Sie auf Erstellen:

Google Cloud Platform – Einrichten eines Projekts

Achten Sie darauf, die Abrechnung zu aktivieren. Öffnen Sie dazu die Registerkarte Abrechnung – Kontoverwaltung im Seitenmenü, wählen Sie das Projekt aus und verknüpfen Sie das Rechnungskonto:

Abrechnung in der Google Cloud Platform

Füllen Sie als Nächstes alle Felder aus, indem Sie Ihre Kontakte und Zahlungskartendetails eingeben. Wenn dies Ihr erstes Projekt auf der GCP ist, erhalten Sie 300 $, die Sie 12 Monate lang nutzen können. Projekte mit 1-2 Google Ads-Konten und bis zu 100.000 Unique Usern pro Monat reichen für ein Jahr. Wenn Sie dieses Limit ausgeschöpft haben, müssen Sie das Geld nicht zurückgeben. Zur weiteren Verwendung füllen Sie einfach das Guthaben auf der Karte auf, die Sie mit dem Projekt verknüpft haben.

Schritt 2. Aktivieren Sie API BigQuery

Nachdem Sie ein Projekt erstellt haben, müssen Sie die BigQuery-API aktivieren. Gehen Sie dazu im Seitenmenü der GCP zu APIs & Services – Dashboard, wählen Sie das Projekt aus und klicken Sie auf APIs und Services aktivieren:

API BigQuery-Aktivierung

Suchen Sie in der API-Bibliothek nach „BigQuery API“ und klicken Sie auf Aktivieren:

API BigQuery aktivieren

Um die API zu verwenden, klicken Sie auf Anmeldeinformationen erstellen:

Anmeldeinformationen erstellen

Wählen Sie in der Dropdown-Liste die BigQuery-API aus und klicken Sie auf Welche Anmeldedaten brauche ich?

Wahl der Anmeldeinformationen

Erstellen Sie den Namen des Dienstkontos und geben Sie die Zugriffsebene für die BigQuery-Rolle an. Wählen Sie den Typ des JSON-Schlüssels aus und klicken Sie auf Weiter:

Anmeldeinformationen angeben

Schritt 3. Aktivieren Sie die Datenübertragungs-API

Als Nächstes müssen Sie den Datendienst in BigQuery aktivieren. Öffnen Sie dazu GBQ und wählen Sie im Seitenmenü auf der linken Seite Transfers aus. Aktivieren Sie dann die BigQuery Data Transfer API:

Aktivieren Sie die BigQuery Data Transfer API

Schritt 4. Bereiten Sie den Datensatz in GBQ vor

Wählen Sie in BigQuery das Projekt aus und klicken Sie rechts auf die Schaltfläche „Dataset erstellen“. Füllen Sie alle erforderlichen Felder für den neuen Datensatz aus (Name, Standort, Aufbewahrung):

Erstellen Sie den Datensatz in GBQ

Schritt 5. Richten Sie die Datenübertragung von Google Ads ein

Klicken Sie im Seitenmenü auf die Registerkarte Übertragungen und dann auf Übertragung erstellen. Wählen Sie dann als Quelle Google Ads (ehemals AdWords) aus und geben Sie den Namen des Uploads ein, beispielsweise Data Transfer.

Unter Zeitplanoptionen können Sie die Standardeinstellung auf Jetzt starten belassen oder das Datum und die Uhrzeit für den Start des Downloads festlegen. Wählen Sie im Feld „Wiederholungen“ aus, wie oft hochgeladen werden soll: täglich, wöchentlich, monatlich bei Bedarf usw.

Datenübertragungseinstellungen

Dann müssen Sie das GBQ-Dataset angeben, in das Berichte aus Google Ads geladen werden sollen. Geben Sie die Kundennummer ein (dies ist die ID Ihres Google Ads-Kontos oder die Kundencenter-ID) und klicken Sie auf Hinzufügen. Sie können die Kundennummer in Ihrem Google Ads-Konto rechts oben neben Ihrer E-Mail-Adresse anzeigen.

Legen Sie die Datenübertragungseinstellungen fest

Dann müssen Sie das von Ihnen verwendete Gmail-Konto autorisieren. Am Folgetag erscheinen die Informationen in dem Datensatz, den Sie bei der Einrichtung der Überweisung angegeben haben.

Als Ergebnis erhalten Sie in GBQ eine große Menge an Rohdaten, mit denen Sie arbeiten können: Tabellen nach Kampagnen, Zielgruppen, allgemeine (benutzerdefinierte) Tabellen, Schlüsselwörter und Conversions. Wenn Sie beispielsweise ein benutzerdefiniertes Dashboard erstellen möchten, können Sie nicht aggregierte Daten aus diesen Tabellen ziehen.

So richten Sie den Upload mit Ads Script ein

Öffnen Sie Ihr Google Ads-Konto, klicken Sie oben rechts auf Tools und Einstellungen, wählen Sie Massenaktionen – Skripts aus und klicken Sie auf das Plus-Symbol:

Skript in Google Ads

Klicken Sie dann in der oberen rechten Ecke auf die Schaltfläche Erweiterte APIs, wählen Sie BigQuery aus und speichern Sie Ihre Änderungen:

Speichern der Änderungen

Achten Sie darauf, sich mit dem Konto anzumelden, mit dem Sie sich bei Google Ads angemeldet haben:

Google Ads-Autorisierung

Kopieren Sie das folgende Skript. Ersetzen Sie in den Zeilen BIGQUERY_PROJECT_ID, BIGQUERY_DATASET_ID und Your email die Werte durch Ihre eigenen Informationen: Projektname, GBQ-Datensatz und E-Mail. Fügen Sie den Skripttext in den Texteditor ein.

    /** * @name Export Data to BigQuery * * @overview The Export Data to BigQuery script sets up a BigQuery * dataset and tables, downloads a report from AdWords and then * loads the report to BigQuery. * * @author AdWords Scripts Team [[email protected]] * * @version 1.3 */ var CONFIG = { BIGQUERY_PROJECT_ID: 'BQ project name', BIGQUERY_DATASET_ID: AdWordsApp.currentAccount().getCustomerId().replace(/-/g, '_'), // Truncate existing data, otherwise will append. TRUNCATE_EXISTING_DATASET: false, TRUNCATE_EXISTING_TABLES: true, // Lists of reports and fields to retrieve from AdWords. REPORTS: [], RECIPIENT_EMAILS: [ 'Your email' ] }; var report = { NAME: 'CLICK_PERFORMANCE_REPORT', //https://developers.google.com/adwords/api/docs/appendix/reports/click-performance-report CONDITIONS: '', FIELDS: {'AccountDescriptiveName': 'STRING', 'AdFormat': 'STRING', 'AdGroupId': 'STRING', 'AdGroupName': 'STRING', 'AoiCountryCriteriaId': 'STRING', 'CampaignId': 'STRING', 'CampaignLocationTargetId': 'STRING', 'CampaignName': 'STRING', 'CampaignStatus': 'STRING', 'Clicks': 'INTEGER', 'ClickType': 'STRING', 'CreativeId': 'STRING', 'CriteriaId': 'STRING', 'CriteriaParameters': 'STRING', 'Date': 'DATE', 'Device': 'STRING', 'ExternalCustomerId': 'STRING', 'GclId': 'STRING', 'KeywordMatchType': 'STRING', 'LopCountryCriteriaId': 'STRING', 'Page': 'INTEGER' }, DATE_RANGE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, ""), DATE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "") }; //Regular export CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //One-time historical export //for(var i=2;i<91;i++){ // report.DATE_RANGE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // report.DATE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //} /** * Main method */ function main() { createDataset(); for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; createTable(reportConfig); } var jobIds = processReports(); waitTillJobsComplete(jobIds); sendEmail(jobIds); } /** * Creates a new dataset. * * If a dataset with the same id already exists and the truncate flag * is set, will truncate the old dataset. If the truncate flag is not * set, then will not create a new dataset. */ function createDataset() { if (datasetExists()) { if (CONFIG.TRUNCATE_EXISTING_DATASET) { BigQuery.Datasets.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, {'deleteContents' : true}); Logger.log('Truncated dataset.'); } else { Logger.log('Dataset %s already exists. Will not recreate.', CONFIG.BIGQUERY_DATASET_ID); return; } } // Create new dataset. var dataSet = BigQuery.newDataset(); dataSet.friendlyName = CONFIG.BIGQUERY_DATASET_ID; dataSet.datasetReference = BigQuery.newDatasetReference(); dataSet.datasetReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; dataSet.datasetReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; dataSet = BigQuery.Datasets.insert(dataSet, CONFIG.BIGQUERY_PROJECT_ID); Logger.log('Created dataset with id %s.', dataSet.id); } /** * Checks if dataset already exists in project. * * @return {boolean} Returns true if dataset already exists. */ function datasetExists() { // Get a list of all datasets in project. var datasets = BigQuery.Datasets.list(CONFIG.BIGQUERY_PROJECT_ID); var datasetExists = false; // Iterate through each dataset and check for an id match. if (datasets.datasets != null) { for (var i = 0; i < datasets.datasets.length; i++) { var dataset = datasets.datasets[i]; if (dataset.datasetReference.datasetId == CONFIG.BIGQUERY_DATASET_ID) { datasetExists = true; break; } } } return datasetExists; } /** * Creates a new table. * * If a table with the same id already exists and the truncate flag * is set, will truncate the old table. If the truncate flag is not * set, then will not create a new table. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. */ function createTable(reportConfig) { var tableName = reportConfig.NAME+reportConfig.DATE; if (tableExists(tableName)) { if (CONFIG.TRUNCATE_EXISTING_TABLES) { BigQuery.Tables.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, tableName); Logger.log('Truncated table %s.', tableName); } else { Logger.log('Table %s already exists. Will not recreate.', tableName); return; } } // Create new table. var table = BigQuery.newTable(); var schema = BigQuery.newTableSchema(); var bigQueryFields = []; // Add each field to table schema. var fieldNames = Object.keys(reportConfig.FIELDS); for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var bigQueryFieldSchema = BigQuery.newTableFieldSchema(); bigQueryFieldSchema.description = fieldName; bigQueryFieldSchema.name = fieldName; bigQueryFieldSchema.type = reportConfig.FIELDS[fieldName]; bigQueryFields.push(bigQueryFieldSchema); } schema.fields = bigQueryFields; table.schema = schema; table.friendlyName = tableName; table.tableReference = BigQuery.newTableReference(); table.tableReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; table.tableReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; table.tableReference.tableId = tableName; table = BigQuery.Tables.insert(table, CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); Logger.log('Created table with id %s.', table.id); } /** * Checks if table already exists in dataset. * * @param {string} tableId The table id to check existence. * * @return {boolean} Returns true if table already exists. */ function tableExists(tableId) { // Get a list of all tables in the dataset. var tables = BigQuery.Tables.list(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); var tableExists = false; // Iterate through each table and check for an id match. if (tables.tables != null) { for (var i = 0; i < tables.tables.length; i++) { var table = tables.tables[i]; if (table.tableReference.tableId == tableId) { tableExists = true; break; } } } return tableExists; } /** * Process all configured reports * * Iterates through each report to: retrieve AdWords data, * backup data to Drive (if configured), load data to BigQuery. * * @return {Array.<string>} jobIds The list of all job ids. */ function processReports() { var jobIds = []; // Iterate over each report type. for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; Logger.log('Running report %s', reportConfig.NAME); // Get data as csv var csvData = retrieveAdwordsReport(reportConfig); //Logger.log(csvData); // Convert to Blob format. var blobData = Utilities.newBlob(csvData, 'application/octet-stream'); // Load data var jobId = loadDataToBigquery(reportConfig, blobData); jobIds.push(jobId); } return jobIds; } /** * Retrieves AdWords data as csv and formats any fields * to BigQuery expected format. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * * @return {string} csvData Report in csv format. */ function retrieveAdwordsReport(reportConfig) { var fieldNames = Object.keys(reportConfig.FIELDS); var query = 'SELECT ' + fieldNames.join(', ') + ' FROM ' + reportConfig.NAME + '' + reportConfig.CONDITIONS + ' DURING ' + reportConfig.DATE_RANGE; Logger.log(query); var report = AdWordsApp.report(query); var rows = report.rows(); var csvRows = []; // Header row csvRows.push(fieldNames.join(',')); // Iterate over each row. while (rows.hasNext()) { var row = rows.next(); var csvRow = []; for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var fieldValue = row[fieldName].toString(); var fieldType = reportConfig.FIELDS[fieldName]; // Strip off % and perform any other formatting here. if (fieldType == 'FLOAT' || fieldType == 'INTEGER') { if (fieldValue.charAt(fieldValue.length - 1) == '%') { fieldValue = fieldValue.substring(0, fieldValue.length - 1); } fieldValue = fieldValue.replace(/,/g,''); if (fieldValue == '--' || fieldValue == 'Unspecified') { fieldValue = '' } } // Add double quotes to any string values. if (fieldType == 'STRING') { if (fieldValue == '--') { fieldValue = '' } fieldValue = fieldValue.replace(/"/g, '""'); fieldValue = '"' + fieldValue + '"' } csvRow.push(fieldValue); } csvRows.push(csvRow.join(',')); } Logger.log('Downloaded ' + reportConfig.NAME + ' with ' + csvRows.length + ' rows.'); return csvRows.join('\n'); } /** * Creates a BigQuery insertJob to load csv data. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * @param {Blob} data Csv report data as an 'application/octet-stream' blob. * * @return {string} jobId The job id for upload. */ function loadDataToBigquery(reportConfig, data) { // Create the data upload job. var job = { configuration: { load: { destinationTable: { projectId: CONFIG.BIGQUERY_PROJECT_ID, datasetId: CONFIG.BIGQUERY_DATASET_ID, tableId: reportConfig.NAME + reportConfig.DATE }, skipLeadingRows: 1 } } }; var insertJob = BigQuery.Jobs.insert(job, CONFIG.BIGQUERY_PROJECT_ID, data); Logger.log('Load job started for %s. Check on the status of it here: ' + 'https://bigquery.cloud.google.com/jobs/%s', reportConfig.NAME, CONFIG.BIGQUERY_PROJECT_ID); return insertJob.jobReference.jobId; } /** * Polls until all jobs are 'DONE'. * * @param {Array.<string>} jobIds The list of all job ids. */ function waitTillJobsComplete(jobIds) { var complete = false; var remainingJobs = jobIds; while (!complete) { if (AdWordsApp.getExecutionInfo().getRemainingTime() < 5){ Logger.log('Script is about to timeout, jobs ' + remainingJobs.join(',') + ' are still incomplete.'); } remainingJobs = getIncompleteJobs(remainingJobs); if (remainingJobs.length == 0) { complete = true; } if (!complete) { Logger.log(remainingJobs.length + ' jobs still being processed.'); // Wait 5 seconds before checking status again. Utilities.sleep(5000); } } Logger.log('All jobs processed.'); } /** * Iterates through jobs and returns the ids for those jobs * that are not 'DONE'. * * @param {Array.<string>} jobIds The list of job ids. * * @return {Array.<string>} remainingJobIds The list of remaining job ids. */ function getIncompleteJobs(jobIds) { var remainingJobIds = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var getJob = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); if (getJob.status.state != 'DONE') { remainingJobIds.push(jobId); } } return remainingJobIds; } /** * Sends a notification email that jobs have completed loading. * * @param {Array.<string>} jobIds The list of all job ids. */ function sendEmail(jobIds) { var html = []; html.push( '<html>', '<body>', '<table width=800 cellpadding=0 border=0 cellspacing=0>', '<tr>', '<td colspan=2 align=right>', "<div style='font: italic normal 10pt Times New Roman, serif; " + "margin: 0; color: #666; padding-right: 5px;'>" + 'Powered by AdWords Scripts</div>', '</td>', '</tr>', "<tr bgcolor='#3c78d8'>", '<td width=500>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>Adwords data load to " + "Bigquery report</div>", '</td>', '<td align=right>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>", AdWordsApp.currentAccount().getCustomerId(), '</tr>', '</table>', '<table width=800 cellpadding=0 border=1 cellspacing=0>', "<tr bgcolor='#ddd'>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>Report</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>JobId</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>Rows</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>State</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>ErrorResult</td>", '</tr>', createTableRows(jobIds), '</table>', '</body>', '</html>'); MailApp.sendEmail(CONFIG.RECIPIENT_EMAILS.join(','), 'Adwords data load to Bigquery Complete', '', {htmlBody: html.join('\n')}); } /** * Creates table rows for email report. * * @param {Array.<string>} jobIds The list of all job ids. */ function createTableRows(jobIds) { var html = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var job = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); var errorResult = '' if (job.status.errorResult) { errorResult = job.status.errorResult; } html.push('<tr>', "<td style='padding: 0px 10px'>" + job.configuration.load.destinationTable.tableId + '</td>', "<td style='padding: 0px 10px'>" + jobId + '</td>', "<td style='padding: 0px 10px'>" + job.statistics.load?job.statistics.load.outputRows:0 + '</td>', "<td style='padding: 0px 10px'>" + job.status.state + '</td>', "<td style='padding: 0px 10px'>" + errorResult + '</td>', '</tr>'); } return html.join('\n'); }
/** * @name Export Data to BigQuery * * @overview The Export Data to BigQuery script sets up a BigQuery * dataset and tables, downloads a report from AdWords and then * loads the report to BigQuery. * * @author AdWords Scripts Team [[email protected]] * * @version 1.3 */ var CONFIG = { BIGQUERY_PROJECT_ID: 'BQ project name', BIGQUERY_DATASET_ID: AdWordsApp.currentAccount().getCustomerId().replace(/-/g, '_'), // Truncate existing data, otherwise will append. TRUNCATE_EXISTING_DATASET: false, TRUNCATE_EXISTING_TABLES: true, // Lists of reports and fields to retrieve from AdWords. REPORTS: [], RECIPIENT_EMAILS: [ 'Your email' ] }; var report = { NAME: 'CLICK_PERFORMANCE_REPORT', //https://developers.google.com/adwords/api/docs/appendix/reports/click-performance-report CONDITIONS: '', FIELDS: {'AccountDescriptiveName': 'STRING', 'AdFormat': 'STRING', 'AdGroupId': 'STRING', 'AdGroupName': 'STRING', 'AoiCountryCriteriaId': 'STRING', 'CampaignId': 'STRING', 'CampaignLocationTargetId': 'STRING', 'CampaignName': 'STRING', 'CampaignStatus': 'STRING', 'Clicks': 'INTEGER', 'ClickType': 'STRING', 'CreativeId': 'STRING', 'CriteriaId': 'STRING', 'CriteriaParameters': 'STRING', 'Date': 'DATE', 'Device': 'STRING', 'ExternalCustomerId': 'STRING', 'GclId': 'STRING', 'KeywordMatchType': 'STRING', 'LopCountryCriteriaId': 'STRING', 'Page': 'INTEGER' }, DATE_RANGE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, ""), DATE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "") }; //Regular export CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //One-time historical export //for(var i=2;i<91;i++){ // report.DATE_RANGE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // report.DATE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //} /** * Main method */ function main() { createDataset(); for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; createTable(reportConfig); } var jobIds = processReports(); waitTillJobsComplete(jobIds); sendEmail(jobIds); } /** * Creates a new dataset. * * If a dataset with the same id already exists and the truncate flag * is set, will truncate the old dataset. If the truncate flag is not * set, then will not create a new dataset. */ function createDataset() { if (datasetExists()) { if (CONFIG.TRUNCATE_EXISTING_DATASET) { BigQuery.Datasets.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, {'deleteContents' : true}); Logger.log('Truncated dataset.'); } else { Logger.log('Dataset %s already exists. Will not recreate.', CONFIG.BIGQUERY_DATASET_ID); return; } } // Create new dataset. var dataSet = BigQuery.newDataset(); dataSet.friendlyName = CONFIG.BIGQUERY_DATASET_ID; dataSet.datasetReference = BigQuery.newDatasetReference(); dataSet.datasetReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; dataSet.datasetReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; dataSet = BigQuery.Datasets.insert(dataSet, CONFIG.BIGQUERY_PROJECT_ID); Logger.log('Created dataset with id %s.', dataSet.id); } /** * Checks if dataset already exists in project. * * @return {boolean} Returns true if dataset already exists. */ function datasetExists() { // Get a list of all datasets in project. var datasets = BigQuery.Datasets.list(CONFIG.BIGQUERY_PROJECT_ID); var datasetExists = false; // Iterate through each dataset and check for an id match. if (datasets.datasets != null) { for (var i = 0; i < datasets.datasets.length; i++) { var dataset = datasets.datasets[i]; if (dataset.datasetReference.datasetId == CONFIG.BIGQUERY_DATASET_ID) { datasetExists = true; break; } } } return datasetExists; } /** * Creates a new table. * * If a table with the same id already exists and the truncate flag * is set, will truncate the old table. If the truncate flag is not * set, then will not create a new table. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. */ function createTable(reportConfig) { var tableName = reportConfig.NAME+reportConfig.DATE; if (tableExists(tableName)) { if (CONFIG.TRUNCATE_EXISTING_TABLES) { BigQuery.Tables.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, tableName); Logger.log('Truncated table %s.', tableName); } else { Logger.log('Table %s already exists. Will not recreate.', tableName); return; } } // Create new table. var table = BigQuery.newTable(); var schema = BigQuery.newTableSchema(); var bigQueryFields = []; // Add each field to table schema. var fieldNames = Object.keys(reportConfig.FIELDS); for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var bigQueryFieldSchema = BigQuery.newTableFieldSchema(); bigQueryFieldSchema.description = fieldName; bigQueryFieldSchema.name = fieldName; bigQueryFieldSchema.type = reportConfig.FIELDS[fieldName]; bigQueryFields.push(bigQueryFieldSchema); } schema.fields = bigQueryFields; table.schema = schema; table.friendlyName = tableName; table.tableReference = BigQuery.newTableReference(); table.tableReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; table.tableReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; table.tableReference.tableId = tableName; table = BigQuery.Tables.insert(table, CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); Logger.log('Created table with id %s.', table.id); } /** * Checks if table already exists in dataset. * * @param {string} tableId The table id to check existence. * * @return {boolean} Returns true if table already exists. */ function tableExists(tableId) { // Get a list of all tables in the dataset. var tables = BigQuery.Tables.list(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); var tableExists = false; // Iterate through each table and check for an id match. if (tables.tables != null) { for (var i = 0; i < tables.tables.length; i++) { var table = tables.tables[i]; if (table.tableReference.tableId == tableId) { tableExists = true; break; } } } return tableExists; } /** * Process all configured reports * * Iterates through each report to: retrieve AdWords data, * backup data to Drive (if configured), load data to BigQuery. * * @return {Array.<string>} jobIds The list of all job ids. */ function processReports() { var jobIds = []; // Iterate over each report type. for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; Logger.log('Running report %s', reportConfig.NAME); // Get data as csv var csvData = retrieveAdwordsReport(reportConfig); //Logger.log(csvData); // Convert to Blob format. var blobData = Utilities.newBlob(csvData, 'application/octet-stream'); // Load data var jobId = loadDataToBigquery(reportConfig, blobData); jobIds.push(jobId); } return jobIds; } /** * Retrieves AdWords data as csv and formats any fields * to BigQuery expected format. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * * @return {string} csvData Report in csv format. */ function retrieveAdwordsReport(reportConfig) { var fieldNames = Object.keys(reportConfig.FIELDS); var query = 'SELECT ' + fieldNames.join(', ') + ' FROM ' + reportConfig.NAME + '' + reportConfig.CONDITIONS + ' DURING ' + reportConfig.DATE_RANGE; Logger.log(query); var report = AdWordsApp.report(query); var rows = report.rows(); var csvRows = []; // Header row csvRows.push(fieldNames.join(',')); // Iterate over each row. while (rows.hasNext()) { var row = rows.next(); var csvRow = []; for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var fieldValue = row[fieldName].toString(); var fieldType = reportConfig.FIELDS[fieldName]; // Strip off % and perform any other formatting here. if (fieldType == 'FLOAT' || fieldType == 'INTEGER') { if (fieldValue.charAt(fieldValue.length - 1) == '%') { fieldValue = fieldValue.substring(0, fieldValue.length - 1); } fieldValue = fieldValue.replace(/,/g,''); if (fieldValue == '--' || fieldValue == 'Unspecified') { fieldValue = '' } } // Add double quotes to any string values. if (fieldType == 'STRING') { if (fieldValue == '--') { fieldValue = '' } fieldValue = fieldValue.replace(/"/g, '""'); fieldValue = '"' + fieldValue + '"' } csvRow.push(fieldValue); } csvRows.push(csvRow.join(',')); } Logger.log('Downloaded ' + reportConfig.NAME + ' with ' + csvRows.length + ' rows.'); return csvRows.join('\n'); } /** * Creates a BigQuery insertJob to load csv data. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * @param {Blob} data Csv report data as an 'application/octet-stream' blob. * * @return {string} jobId The job id for upload. */ function loadDataToBigquery(reportConfig, data) { // Create the data upload job. var job = { configuration: { load: { destinationTable: { projectId: CONFIG.BIGQUERY_PROJECT_ID, datasetId: CONFIG.BIGQUERY_DATASET_ID, tableId: reportConfig.NAME + reportConfig.DATE }, skipLeadingRows: 1 } } }; var insertJob = BigQuery.Jobs.insert(job, CONFIG.BIGQUERY_PROJECT_ID, data); Logger.log('Load job started for %s. Check on the status of it here: ' + 'https://bigquery.cloud.google.com/jobs/%s', reportConfig.NAME, CONFIG.BIGQUERY_PROJECT_ID); return insertJob.jobReference.jobId; } /** * Polls until all jobs are 'DONE'. * * @param {Array.<string>} jobIds The list of all job ids. */ function waitTillJobsComplete(jobIds) { var complete = false; var remainingJobs = jobIds; while (!complete) { if (AdWordsApp.getExecutionInfo().getRemainingTime() < 5){ Logger.log('Script is about to timeout, jobs ' + remainingJobs.join(',') + ' are still incomplete.'); } remainingJobs = getIncompleteJobs(remainingJobs); if (remainingJobs.length == 0) { complete = true; } if (!complete) { Logger.log(remainingJobs.length + ' jobs still being processed.'); // Wait 5 seconds before checking status again. Utilities.sleep(5000); } } Logger.log('All jobs processed.'); } /** * Iterates through jobs and returns the ids for those jobs * that are not 'DONE'. * * @param {Array.<string>} jobIds The list of job ids. * * @return {Array.<string>} remainingJobIds The list of remaining job ids. */ function getIncompleteJobs(jobIds) { var remainingJobIds = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var getJob = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); if (getJob.status.state != 'DONE') { remainingJobIds.push(jobId); } } return remainingJobIds; } /** * Sends a notification email that jobs have completed loading. * * @param {Array.<string>} jobIds The list of all job ids. */ function sendEmail(jobIds) { var html = []; html.push( '<html>', '<body>', '<table width=800 cellpadding=0 border=0 cellspacing=0>', '<tr>', '<td colspan=2 align=right>', "<div style='font: italic normal 10pt Times New Roman, serif; " + "margin: 0; color: #666; padding-right: 5px;'>" + 'Powered by AdWords Scripts</div>', '</td>', '</tr>', "<tr bgcolor='#3c78d8'>", '<td width=500>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>Adwords data load to " + "Bigquery report</div>", '</td>', '<td align=right>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>", AdWordsApp.currentAccount().getCustomerId(), '</tr>', '</table>', '<table width=800 cellpadding=0 border=1 cellspacing=0>', "<tr bgcolor='#ddd'>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>Report</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>JobId</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>Rows</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>State</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>ErrorResult</td>", '</tr>', createTableRows(jobIds), '</table>', '</body>', '</html>'); MailApp.sendEmail(CONFIG.RECIPIENT_EMAILS.join(','), 'Adwords data load to Bigquery Complete', '', {htmlBody: html.join('\n')}); } /** * Creates table rows for email report. * * @param {Array.<string>} jobIds The list of all job ids. */ function createTableRows(jobIds) { var html = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var job = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); var errorResult = '' if (job.status.errorResult) { errorResult = job.status.errorResult; } html.push('<tr>', "<td style='padding: 0px 10px'>" + job.configuration.load.destinationTable.tableId + '</td>', "<td style='padding: 0px 10px'>" + jobId + '</td>', "<td style='padding: 0px 10px'>" + job.statistics.load?job.statistics.load.outputRows:0 + '</td>', "<td style='padding: 0px 10px'>" + job.status.state + '</td>', "<td style='padding: 0px 10px'>" + errorResult + '</td>', '</tr>'); } return html.join('\n'); }

Bevor Sie das Skript ausführen, klicken Sie unbedingt auf die Schaltfläche Vorschau in der unteren rechten Ecke, um das Ergebnis zu überprüfen. Wenn es Fehler enthält, warnt Sie das System und gibt an, in welcher Zeile es aufgetreten ist, wie in diesem Screenshot:

Führen Sie das Skript aus

Wenn keine Fehler vorliegen, klicken Sie auf die Schaltfläche Ausführen:

Richten Sie den Upload von Google Ads ein

Als Ergebnis erhalten Sie einen neuen CLICK_PERFORMANCE_REPORT-Bericht in Ihrem GBQ, der am nächsten Tag verfügbar sein wird:

ergibt GBQ

Denken Sie daran, dass Sie bei der Verwendung von Data Transfer eine große Menge an nicht aggregierten Rohdaten erhalten. Mit Ads Script haben Sie nur Informationen zu bestimmten Feldern.

Die folgenden Felder aus diesem Upload werden in die sitzungsbezogenen OWOX BI-Tabellen aufgenommen:

  • GclId
  • Kampagnen-ID
  • Kampagnenname
  • Anzeigengruppen-ID
  • Anzeigengruppenname
  • Kriterien-ID
  • KriterienParameter
  • KeywordMatchType

So verbinden Sie den Datendownload von Google Ads mit OWOX BI

Jetzt müssen Sie Informationen aus Google Ads mit Website-Daten kombinieren, um zu verstehen, über welche Kampagnen Nutzer auf Ihre Website gelangt sind. Die Tabellen, die Sie in BigQuery erhalten, z. B. Data Transfer, haben keinen Client-ID-Parameter. Sie können nur feststellen, welcher Kunde auf Anzeigen geklickt hat, indem Sie die gclid-Daten mit den OWOX BI-Flussdaten verknüpfen.

Wenn Sie noch keine Google Analytics → Google BigQuery-Streaming-Pipeline in OWOX BI haben, lesen Sie die Anweisungen zur Erstellung.

Gehen Sie dann zu Ihrem OWOX BI-Projekt und öffnen Sie diese Pipeline. Klicken Sie auf die Registerkarte Einstellungen und dann unter Sitzungsdatenerfassung auf Einstellungen bearbeiten:

OWOX BI-Pipeline-Einstellungen

Verwenden Sie den Schieberegler, um die Datenerfassung für automatisch gekennzeichnete Google Ads-Kampagnen zu aktivieren, und klicken Sie auf Einstellungen ändern:

Datenerfassung für Google Ads aktivieren

Wählen Sie den AutoLabel-Markuptyp aus und geben Sie an, wie die Datenübertragungs- oder Ads-Skripts in BigQuery geladen werden sollen. Geben Sie das Projekt und den Datensatz an, aus dem Google Ads-Daten heruntergeladen werden, und speichern Sie Ihre Einstellungen:

Speichern Sie die Einstellungen

Nützliche Tipps

Tipp 1. Mit Data Transfer können Sie Verlaufsdaten von Google Ads auf GBQ hochladen. Gleichzeitig gibt es keine Beschränkungen für die Gesamtladezeit (entweder für ein Jahr oder für drei), sondern mit Daten für jeweils nur 180 Tage.

Sie können den Upload aktivieren und den Zeitraum mit der Schaltfläche „Backfill planen“ auf der Registerkarte „Transfers“ festlegen, indem Sie den gewünschten Transfer auswählen:

historische Daten hochladen

Tipp 2. Wenn Sie die Anzahl der Google Ads-Konten überprüfen möchten, für die GCP Gebühren berechnet, müssen Sie die Anzahl der ExternalCustomerID in der Customer-Tabelle mithilfe der Abfrage ermitteln:

    SELECT ExternalCustomerId FROM `project_name.dataset_name.Customer_*` WHERE _PARTITIONTIME >= "2020-01-01 00:00:00" AND _PARTITIONTIME < "2020-07-10 00:00:00" group by 1
SELECT ExternalCustomerId FROM `project_name.dataset_name.Customer_*` WHERE _PARTITIONTIME >= "2020-01-01 00:00:00" AND _PARTITIONTIME < "2020-07-10 00:00:00" group by 1

Sie können die Daten in der Abfrage bearbeiten.

Tipp 3. Sie können selbst über SQL-Abfragen auf die hochgeladenen Daten zugreifen. Hier ist beispielsweise eine Abfrage zur Bestimmung der Effektivität von Kampagnen aus den von der Datenübertragung abgeleiteten Tabellen "Campaign" und "CampaignBasicStats":

    SELECT {source language="sql"} c.ExternalCustomerId, c.CampaignName, c.CampaignStatus, SUM(cs.Impressions) AS Impressions, SUM(cs.Interactions) AS Interactions, {/source} (SUM(cs.Cost) / 1000000) AS Cost FROM `[DATASET].Campaign_[CUSTOMER_ID]` c LEFT JOIN {source language="sql"} {source language="sql"} `[DATASET].CampaignBasicStats_[CUSTOMER_ID]` cs ON (c.CampaignId = cs.CampaignId AND cs._DATA_DATE BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -31 DAY) AND DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) WHERE c._DATA_DATE = c._LATEST_DATE GROUP BY 1, 2, 3 ORDER BY Impressions DESC
SELECT {source language="sql"} c.ExternalCustomerId, c.CampaignName, c.CampaignStatus, SUM(cs.Impressions) AS Impressions, SUM(cs.Interactions) AS Interactions, {/source} (SUM(cs.Cost) / 1000000) AS Cost FROM `[DATASET].Campaign_[CUSTOMER_ID]` c LEFT JOIN {source language="sql"} {source language="sql"} `[DATASET].CampaignBasicStats_[CUSTOMER_ID]` cs ON (c.CampaignId = cs.CampaignId AND cs._DATA_DATE BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -31 DAY) AND DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) WHERE c._DATA_DATE = c._LATEST_DATE GROUP BY 1, 2, 3 ORDER BY Impressions DESC

PS Wenn Sie Hilfe beim Hochladen und Zusammenführen von Daten in Google BigQuery benötigen, helfen wir Ihnen gerne weiter. Melden Sie sich für eine Demo an – und wir besprechen die Details.

MELDEN SIE SICH FÜR EINE DEMO AN