So laden Sie Rohdaten von Google Ads in Google BigQuery hoch
Veröffentlicht: 2022-04-12Durch 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.
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.

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.
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.

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:

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:

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:

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

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

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

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:

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:

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):

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.

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.

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:

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

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

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:


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

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

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:

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

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:

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:

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 1Sie 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.
