├── .gitignore
├── package.json
├── LICENSE.txt
├── get-accounts.sql
├── bq_queries
├── 20-placements_view.sql
├── 14-poor_assets_summary.sql
├── 06-assetssnapshots.sql
├── 13-campaign_scores_union.sql
├── 09-bpscore.sql
├── 05-video_assets.sql
├── 19-assetgroupperformance.sql
├── 08-assetsummary.sql
├── 03-primary_conversion_action_search.sql
├── 02-primary_conversion_action_pmax.sql
├── 04-text_assets.sql
├── 12-campaign_settings.sql
├── 01-image_assets.sql
├── 11-assetgroupbestpracticessnapshots.sql
├── 10-assetgroupbestpractices.sql
└── 07-campaign_data.sql
├── google_ads_queries
├── customer.sql
├── conversions.sql
├── ad_group_asset.sql
├── ocid_mapping.sql
├── custom_goal_names.sql
├── assetgroupsignal.sql
├── recommendations.sql
├── conversion_category.sql
├── customerasset.sql
├── campaignasset.sql
├── conversion_custom.sql
├── conversion_split.sql
├── pmax_placement_view.sql
├── tcpa_search.sql
├── assetgroupsummary.sql
├── assetgroupasset.sql
├── campaignconversionaction.sql
└── campaign_settings.sql
├── non_retail_to_retail_upgrade.sh
├── plugins
└── retail
│ ├── bq_queries
│ ├── 17-shopping_productgroupsummary.sql
│ ├── 15-campaign_conversion_action_name.sql
│ ├── 16-shopping_campaignproducttype.sql
│ └── 18-shopping_lowclicks_highroas_producttype.sql
│ └── google_ads_queries
│ └── shoppingperformance_view.sql
├── setup-wfs.sh
├── CONTRIBUTING.md
├── answers.json
├── upgrade_pmaximizer.sh
├── no_gmc_update.sh
├── walkthrough.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | work_retail/
2 | node_modules
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pmaximizer",
3 | "main": "index.js",
4 | "author": "",
5 | "license": "ISC",
6 | "dependencies": {
7 | "lsd-cloner": "^1.0.3"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2022 Google LLC
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | https://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/get-accounts.sql:
--------------------------------------------------------------------------------
1 | -- Copyright 2022 Google LLC
2 | --
3 | -- Licensed under the Apache License, Version 2.0 (the "License");
4 | -- you may not use this file except in compliance with the License.
5 | -- You may obtain a copy of the License at
6 | --
7 | -- https://www.apache.org/licenses/LICENSE-2.0
8 | --
9 | -- Unless required by applicable law or agreed to in writing, software
10 | -- distributed under the License is distributed on an "AS IS" BASIS,
11 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | -- See the License for the specific language governing permissions and
13 | -- limitations under the License.
14 |
15 | SELECT customer.id
16 | FROM campaign
17 | WHERE campaign.advertising_channel_type = "PERFORMANCE_MAX"
--------------------------------------------------------------------------------
/bq_queries/20-placements_view.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.placements_view` AS
16 | SELECT
17 | *
18 | FROM `{bq_dataset}.pmax_placement_view`
--------------------------------------------------------------------------------
/google_ads_queries/customer.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.id as account_id,
17 | customer.descriptive_name as account_name,
18 | customer.currency_code as currency
19 | FROM customer
--------------------------------------------------------------------------------
/google_ads_queries/conversions.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | conversion_action.name AS conversion_action,
17 | conversion_action.type AS conversion_type,
18 | customer.id AS account_id
19 | FROM conversion_action
--------------------------------------------------------------------------------
/google_ads_queries/ad_group_asset.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | asset.id AS asset_id,
17 | ad_group_asset.ad_group~0 AS ad_group_id,
18 | customer.id AS account_id,
19 | ad_group_asset.field_type AS asset_type
20 | FROM
21 | ad_group_asset
--------------------------------------------------------------------------------
/google_ads_queries/ocid_mapping.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | -- This is a GAARF capability that makes it possible
17 | -- to add links to the dashboard later.
18 | -- GAARF docs: https://github.com/google/ads-api-report-fetcher
19 | SELECT * FROM builtin.ocid_mapping
--------------------------------------------------------------------------------
/google_ads_queries/custom_goal_names.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.id AS account_id,
17 | custom_conversion_goal.id AS custom_conversion_goal_id,
18 | custom_conversion_goal.name AS custom_conversion_goal_name
19 | FROM custom_conversion_goal
20 |
--------------------------------------------------------------------------------
/non_retail_to_retail_upgrade.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2022 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | set -e
17 |
18 | git pull
19 | source ./build-retail.sh
20 |
21 | echo "Now upgrading from non-retail version to retail version by re-installing."
22 | npm init gaarf-wf@latest -- --answers=answers.json
--------------------------------------------------------------------------------
/google_ads_queries/assetgroupsignal.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | asset_group_signal.audience.audience AS audience_signals,
17 | campaign.id AS campaign_id,
18 | asset_group.id AS asset_group_id
19 | FROM
20 | asset_group_signal
21 | WHERE
22 | asset_group_signal.audience.audience IS NOT NULL
23 |
--------------------------------------------------------------------------------
/google_ads_queries/recommendations.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.id as account_id,
17 | campaign.id as campaign_id,
18 | recommendation.type as rec_type
19 | FROM
20 | recommendation
21 | WHERE
22 | campaign.advertising_channel_type = 'PERFORMANCE_MAX'
23 | AND recommendation.type in ('CAMPAIGN_BUDGET', 'FORECASTING_CAMPAIGN_BUDGET')
--------------------------------------------------------------------------------
/bq_queries/14-poor_assets_summary.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.poor_assets_summary` AS
16 | SELECT
17 | COUNT(distinct ABP.campaign_id) AS num_campaigns,
18 | COUNT(distinct ABP.asset_group_id) AS num_asset_groups
19 | FROM `{bq_dataset}_bq.assetgroupbestpractices` ABP
20 | WHERE ad_strength = 'POOR'
21 |
--------------------------------------------------------------------------------
/google_ads_queries/conversion_category.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | campaign.id AS campaign_id,
17 | customer.id AS account_id,
18 | campaign_conversion_goal.category AS conversion_name,
19 | campaign.advertising_channel_type AS campaign_type
20 | FROM campaign_conversion_goal
21 | WHERE campaign.advertising_channel_type IN ("PERFORMANCE_MAX", "SEARCH")
22 | AND campaign_conversion_goal.biddable = true
23 |
--------------------------------------------------------------------------------
/google_ads_queries/customerasset.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | SELECT
17 | customer.descriptive_name AS account_name,
18 | campaign.id AS campaign_id,
19 | customer.id AS account_id,
20 | customer_asset.asset AS asset,
21 | customer_asset.field_type AS asset_type,
22 | customer_asset.primary_status AS asset_primary_status,
23 | customer_asset.status AS asset_status,
24 | FROM customer_asset
25 | WHERE segments.date >= "{start_date}"
26 | AND segments.date <= "{end_date}"
--------------------------------------------------------------------------------
/google_ads_queries/campaignasset.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.descriptive_name as account_name,
17 | campaign.id as campaign_id,
18 | customer.id as account_id,
19 | campaign.name as campaign_name,
20 | campaign.advertising_channel_type as campaign_type,
21 | campaign.status as campaign_status,
22 | campaign_asset.field_type as asset_type
23 | FROM campaign_asset
24 | WHERE campaign.advertising_channel_type = 'PERFORMANCE_MAX'
25 | AND campaign.status = 'ENABLED'
--------------------------------------------------------------------------------
/google_ads_queries/conversion_custom.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | campaign.id AS campaign_id,
17 | conversion_goal_campaign_config.custom_conversion_goal~0 AS custom_conversion_goal_id,
18 | customer.id AS account_id,
19 | campaign.advertising_channel_type AS campaign_type
20 | FROM conversion_goal_campaign_config
21 | WHERE campaign.advertising_channel_type IN ("PERFORMANCE_MAX", "SEARCH")
22 | AND conversion_goal_campaign_config.custom_conversion_goal IS NOT NULL
23 |
--------------------------------------------------------------------------------
/google_ads_queries/conversion_split.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | segments.date AS date,
17 | campaign.id AS campaign_id,
18 | segments.conversion_action~0 AS conversion_action_id,
19 | segments.conversion_action_name AS conversion_name,
20 | metrics.conversions AS conversions,
21 | customer.id as account_id,
22 | campaign.advertising_channel_type AS campaign_type
23 | FROM ad_group_ad
24 | WHERE
25 | segments.date >= "{start_date}"
26 | AND segments.date <= "{end_date}"
27 | AND campaign.advertising_channel_type IN ('PERFORMANCE_MAX', 'SEARCH')
--------------------------------------------------------------------------------
/plugins/retail/bq_queries/17-shopping_productgroupsummary.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.shopping_productgroupsummary`
16 | AS (
17 | SELECT
18 | date,
19 | product_type,
20 | SUM(clicks) AS clicks,
21 | SUM(impressions) AS impressions,
22 | # ctr = clicks/impressions*100
23 | SUM(sum_cost) AS sum_cost,
24 | SUM(sum_conversions_value) AS sum_conversions_value
25 | # roas = conversions_value/cost
26 | FROM
27 | `{bq_dataset}_bq.shopping_campaignproducttype`
28 | GROUP BY 1, 2
29 | )
30 |
--------------------------------------------------------------------------------
/setup-wfs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2022 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | set -e
17 |
18 |
19 | until [[ "$yn" == [YyNn] ]]; do
20 | msg='Do you operate a retail business and wish to gain product insights with our retail-focused pMaximizer?'
21 | msg+=' Please respond with 'y' for yes or 'n' for no: '
22 | read -p "$msg" yn
23 | done
24 |
25 | if [[ "$yn" == "y" || "$yn" == "Y" ]]; then
26 | source ./build-retail.sh
27 | else
28 | echo "skipping Retail setup..."
29 | fi
30 |
31 | echo "initializing Google Ads data ETL Workflow..."
32 | npm init gaarf-wf@latest -- --answers=answers.json
33 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project.
4 |
5 | ## Before you begin
6 |
7 | ### Sign our Contributor License Agreement
8 |
9 | Contributions to this project must be accompanied by a
10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA).
11 | You (or your employer) retain the copyright to your contribution; this simply
12 | gives us permission to use and redistribute your contributions as part of the
13 | project.
14 |
15 | If you or your current employer have already signed the Google CLA (even if it
16 | was for a different project), you probably don't need to do it again.
17 |
18 | Visit to see your current agreements or to
19 | sign a new one.
20 |
21 | ### Review our Community Guidelines
22 |
23 | This project follows
24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
25 |
26 | ## Contribution process
27 |
28 | ### Code Reviews
29 |
30 | All submissions, including submissions by project members, require review. We
31 | use GitHub pull requests for this purpose. Consult
32 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
33 | information on using pull requests.
34 |
--------------------------------------------------------------------------------
/plugins/retail/bq_queries/15-campaign_conversion_action_name.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 |
17 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.campaign_conversion_action_name` AS (
18 | SELECT
19 | date,
20 | account_id,
21 | account_name,
22 | campaign_id,
23 | campaign_name,
24 | conversion_action_name,
25 | conversion_action_category,
26 | sum(all_conversions) AS all_conversions,
27 | sum(all_conversions_value) AS all_conversions_value,
28 | sum(conversions) AS conversions,
29 | sum(view_through_conversions) AS view_thrupgh_conversions,
30 | sum(value_per_conversion) AS value_per_conversion
31 | FROM `{bq_dataset}.campaignconversionaction`
32 | GROUP BY 1, 2, 3, 4, 5, 6, 7
33 | )
--------------------------------------------------------------------------------
/answers.json:
--------------------------------------------------------------------------------
1 | {
2 | "use_current_project": true,
3 | "name": "pmax",
4 | "gcs_bucket": "",
5 | "service_account": "",
6 | "path_to_ads_queries": "google_ads_queries",
7 | "path_to_bq_queries": "bq_queries",
8 | "custom_ids_query_path": "get-accounts.sql",
9 | "path_to_googleads_config": "google-ads.yaml",
10 | "cf_memory": "2048MB",
11 | "deploy_scripts": true,
12 | "deploy_wf": true,
13 | "output_dataset": "pmax_ads",
14 | "ads_macro": {
15 | "start_date": ":YYYYMMDD-90",
16 | "end_date": ":YYYYMMDD-1"
17 | },
18 | "bq_macro": {
19 | "bq_dataset": "pmax_ads"
20 | },
21 | "schedule_wf": true,
22 | "schedule_time": "04:00",
23 | "run_job": false,
24 | "run_wf": true,
25 | "clone_dashboard": true,
26 | "dashboard_id": "6e773f65-7612-45af-af37-e3cab6a9828b",
27 | "dashboard_name": "pMaximizer",
28 | "dashboard_dataset": "pmax_ads_bq",
29 | "dashboard_datasources": {
30 | "poor_assets": "poor_assets_summary",
31 | "campaign_settings": "campaign_settings",
32 | "campaign_setup": "campaign_data",
33 | "asset_group_bp": "assetgroupbestpractices",
34 | "asset_performance_snapshots": "assetssnapshots_*",
35 | "assets_performance": "summaryassets",
36 | "scores": "campaign_scores_union",
37 | "asset_group_performance": "assetgroup_performance",
38 | "placements_view": "placements_view"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/bq_queries/06-assetssnapshots.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.assetssnapshots_${format(yesterday(),'yyyyMMdd')}` AS (
16 | SELECT
17 | CURRENT_DATE()-1 as day,
18 | AGA.account_id,
19 | AGA.account_name,
20 | AGA.asset_group_id,
21 | AGA.asset_group_name,
22 | AGA.campaign_name,
23 | AGA.campaign_id,
24 | AGA.asset_id,
25 | AGA.asset_sub_type,
26 | AGA.asset_performance,
27 | AGA.text_asset_text,
28 | COALESCE(AGA.image_url,CONCAT('https://www.youtube.com/watch?v=',AGA.video_id)) AS image_video,
29 | COALESCE(AGA.image_url,CONCAT('https://i.ytimg.com/vi/', CONCAT(AGA.video_id, '/hqdefault.jpg'))) AS image_video_url
30 | FROM {bq_dataset}.assetgroupasset AGA
31 | WHERE asset_performance NOT IN ('PENDING','UNKNOWN')
32 | GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13)
33 |
--------------------------------------------------------------------------------
/google_ads_queries/pmax_placement_view.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | segments.date AS date,
17 | campaign.advertising_channel_type AS campaign_type,
18 | campaign.status AS campaign_status,
19 | customer.id AS account_id,
20 | customer.descriptive_name AS account_name,
21 | campaign.id AS campaign_id,
22 | campaign.name AS campaign_name,
23 | performance_max_placement_view.display_name AS placement_name,
24 | performance_max_placement_view.placement AS placement,
25 | performance_max_placement_view.placement_type AS placement_type,
26 | performance_max_placement_view.target_url AS placement_target_url,
27 | metrics.impressions AS impressions
28 | FROM performance_max_placement_view
29 | WHERE campaign.advertising_channel_type = "PERFORMANCE_MAX"
30 | AND segments.date >= "{start_date}"
31 | AND segments.date <= "{end_date}"
32 | AND campaign.status = 'ENABLED'
--------------------------------------------------------------------------------
/google_ads_queries/tcpa_search.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.id as account_id,
17 | campaign.id as campaign_id,
18 | segments.conversion_action~0 AS conversion_action_id,
19 | segments.conversion_action_name AS conversion_name,
20 | bidding_strategy.maximize_conversion_value.target_roas AS bidding_strategy_mcv_troas,
21 | bidding_strategy.target_roas.target_roas AS bidding_strategy_troas,
22 | bidding_strategy.maximize_conversions.target_cpa_micros AS bidding_strategy_mc_tcpa,
23 | bidding_strategy.target_cpa.target_cpa_micros AS bidding_strategy_tcpa,
24 | campaign.maximize_conversions.target_cpa_micros AS campaign_mc_tcpa,
25 | campaign.target_cpa.target_cpa_micros AS campaign_tcpa,
26 | campaign.maximize_conversion_value.target_roas AS campaign_mcv_troas,
27 | campaign.target_roas.target_roas AS campaign_troas
28 | FROM
29 | campaign
30 | WHERE
31 | campaign.advertising_channel_type = 'SEARCH'
--------------------------------------------------------------------------------
/upgrade_pmaximizer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2022 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | #This is a script to update code from git and re-run all queries for retail-pmax users.
18 | set -e
19 |
20 | WORK_RETAIL="work_retail"
21 |
22 | git pull
23 |
24 | #Check if the user deployed the retail version of pMaximizer. If so, work from there.
25 | if [ -d "$WORK_RETAIL" ]; then
26 | ./build-retail.sh
27 | cd "$WORK_RETAIL"
28 | fi
29 |
30 | # This will trigger an update of gaarf, our underlying ETL library
31 | ./deploy-wf.sh
32 |
33 | if [ -f "./deploy-queries.sh" ]; then
34 | # If deploy-queries.sh exists, run it
35 | ./deploy-queries.sh
36 | else
37 | # If deploy-queries.sh does not exist, run deploy-scripts.sh
38 | ./deploy-scripts.sh
39 | fi
40 | ./run-wf.sh
41 |
42 | echo "generating a new up-to-date copy of our main template..."
43 | # This will use our answers.json to generate a new template
44 | npm install
45 | npx lsd-cloner --answers=answers.json
--------------------------------------------------------------------------------
/bq_queries/13-campaign_scores_union.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.campaign_scores_union` AS
16 | WITH
17 | score_types AS
18 | (
19 | SELECT 'Video Score' AS score_type UNION ALL
20 | SELECT 'Image Score' UNION ALL
21 | SELECT 'Text Score' UNION ALL
22 | SELECT 'Campaign Best Practice Score'
23 | ),
24 |
25 | scores_union AS
26 | (
27 | SELECT
28 | `date`,
29 | campaign_name,
30 | video_score,
31 | image_score,
32 | text_score,
33 | campaign_bp_score,
34 | S.score_type AS score_type
35 | FROM `{bq_dataset}_bq.campaign_settings`
36 | CROSS JOIN score_types S
37 | )
38 |
39 | SELECT
40 | `date`,
41 | campaign_name,
42 | score_type,
43 | CASE score_type
44 | WHEN "Video Score" THEN video_score
45 | WHEN "Image Score" THEN image_score
46 | WHEN "Text Score" THEN text_score
47 | WHEN "Campaign Best Practice Score" THEN campaign_bp_score
48 | ELSE NULL
49 | END AS score
50 | FROM scores_union
51 |
--------------------------------------------------------------------------------
/bq_queries/09-bpscore.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.campaignbpscore_${format(today(),'yyyyMMdd')}` AS
16 | (
17 | SELECT
18 | date,
19 | CD.account_id,
20 | CD.account_name,
21 | CD.campaign_id,
22 | CD.campaign_name,
23 | round(
24 | (
25 | IF(CD.url_expansion_opt_out=true,1,0) +
26 | CD.audience_signals_score +
27 | IF(CD.missing_sitelinks=0,1,missing_sitelinks/4) +
28 | CASE
29 | WHEN positive_geo_target_type_configured_good='X' AND negative_geo_target_type_configured_good='X' THEN 0
30 | WHEN positive_geo_target_type_configured_good='Yes' AND negative_geo_target_type_configured_good='X' THEN 0.5
31 | WHEN positive_geo_target_type_configured_good='X' AND negative_geo_target_type_configured_good='Yes' THEN 0.5
32 | WHEN positive_geo_target_type_configured_good='Yes' AND negative_geo_target_type_configured_good='Yes' THEN 1
33 | END
34 | )/4,2
35 | ) AS campaign_bp_score
36 | FROM `{bq_dataset}_bq.campaign_data`AS CD
37 | GROUP BY 1,2,3,4,5,6
38 | )
--------------------------------------------------------------------------------
/plugins/retail/google_ads_queries/shoppingperformance_view.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | customer.descriptive_name as account_name,
17 | customer.id as account_id,
18 | campaign.advertising_channel_type,
19 | campaign.id AS campaign_id,
20 | campaign.name AS campaign_name,
21 | campaign.status AS campaign_status,
22 | segments.date AS date,
23 | segments.product_type_l1 AS product_type_l1,
24 | segments.product_type_l2 AS product_type_l2,
25 | segments.product_type_l3 AS product_type_l3,
26 | segments.product_type_l4 AS product_type_l4,
27 | segments.product_type_l5 AS product_type_l5,
28 | metrics.ctr AS ctr,
29 | metrics.clicks AS clicks,
30 | metrics.conversions AS conversions,
31 | metrics.impressions AS impressions,
32 | metrics.conversions_value AS conversions_value,
33 | metrics.cost_micros AS cost
34 | FROM shopping_performance_view
35 | WHERE campaign.advertising_channel_type = "PERFORMANCE_MAX"
36 | AND segments.date >= "{start_date}"
37 | AND segments.date <= "{end_date}"
38 | AND campaign.status = 'ENABLED'
--------------------------------------------------------------------------------
/bq_queries/05-video_assets.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.video_assets`
16 | AS (
17 | WITH asset_group_with_videos AS(
18 | SELECT DISTINCT AGA.asset_group_id
19 | FROM `{bq_dataset}.assetgroupasset` AS AGA
20 | WHERE AGA.asset_type = 'YOUTUBE_VIDEO'
21 | AND AGA.video_id IS NOT NULL
22 | AND AGA.video_id != ''
23 | ),
24 | count_videos AS (
25 | SELECT
26 | campaign_id,
27 | asset_group_id,
28 | COUNT(*) AS count_videos
29 | FROM `{bq_dataset}.assetgroupasset`
30 | WHERE asset_type = 'YOUTUBE_VIDEO'
31 | GROUP BY 1, 2
32 | )
33 | SELECT DISTINCT
34 | AGS.account_id,
35 | AGS.account_name,
36 | AGS.campaign_id,
37 | AGS.campaign_name,
38 | AGS.asset_group_id,
39 | AGS.asset_group_name,
40 | AGS.ad_strength,
41 | IF(AGV.asset_group_id IS NULL, "X", "Yes") AS is_video_uploaded,
42 | COALESCE(CV.count_videos,0) AS count_videos
43 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
44 | LEFT JOIN asset_group_with_videos AS AGV USING (asset_group_id)
45 | LEFT JOIN count_videos CV USING (campaign_id,asset_group_id)
46 | )
47 |
--------------------------------------------------------------------------------
/google_ads_queries/assetgroupsummary.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | segments.date AS date,
17 | asset_group.id AS asset_group_id,
18 | asset_group.name AS asset_group_name,
19 | asset_group.status AS asset_group_status,
20 | campaign.id AS campaign_id,
21 | campaign.name AS campaign_name,
22 | customer.id AS account_id,
23 | customer.descriptive_name AS account_name,
24 | asset_group.ad_strength AS ad_strength,
25 | metrics.clicks AS clicks,
26 | metrics.conversions AS conversions,
27 | metrics.all_conversions AS all_conversions,
28 | metrics.cost_micros As cost,
29 | metrics.conversions_value AS conversions_value,
30 | metrics.impressions AS impressions,
31 | metrics.ctr AS ctr,
32 | metrics.value_per_all_conversions AS value_per_all_conversions,
33 | metrics.value_per_conversion AS value_per_conversion,
34 | metrics.all_conversions_value AS all_conversions_value,
35 | FROM
36 | asset_group
37 | WHERE
38 | campaign.advertising_channel_type = 'PERFORMANCE_MAX'
39 | AND asset_group.status = 'ENABLED'
40 | AND campaign.status = 'ENABLED'
41 | AND segments.date >= '{start_date}'
42 | AND segments.date <= '{end_date}'
--------------------------------------------------------------------------------
/google_ads_queries/assetgroupasset.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | asset_group.id AS asset_group_id,
17 | asset_group.name AS asset_group_name,
18 | asset_group.status AS asset_group_status,
19 | campaign.id AS campaign_id,
20 | campaign.name AS campaign_name,
21 | asset.id AS asset_id,
22 | customer.id AS account_id,
23 | customer.descriptive_name AS account_name,
24 | asset.type AS asset_type,
25 | asset_group_asset.field_type AS asset_sub_type,
26 | asset_group_asset.performance_label as asset_performance,
27 | asset.image_asset.file_size AS image_file_size,
28 | asset.image_asset.full_size.url AS image_url,
29 | asset.text_asset.text AS text_asset_text,
30 | asset.image_asset.full_size.height_pixels AS image_height,
31 | asset.image_asset.full_size.width_pixels AS image_width,
32 | asset.youtube_video_asset.youtube_video_id AS video_id,
33 | asset.youtube_video_asset.youtube_video_title AS video_title
34 | FROM asset_group_asset
35 | WHERE campaign.advertising_channel_type = 'PERFORMANCE_MAX'
36 | AND campaign.status = 'ENABLED'
37 | AND asset_group.status = 'ENABLED'
38 | AND asset_group_asset.status = 'ENABLED'
39 | AND asset_group_asset.source = 'ADVERTISER'
--------------------------------------------------------------------------------
/bq_queries/19-assetgroupperformance.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.assetgroup_performance` AS (
17 | WITH
18 | LOW_ASSETS AS (
19 | SELECT
20 | asset_group_id,
21 | COUNT(*) AS sum_of_low_perf_assets
22 | FROM `{bq_dataset}_bq.summaryassets`
23 | WHERE asset_performance = 'LOW'
24 | GROUP BY asset_group_id
25 | )
26 | SELECT
27 | AGS.date,
28 | AGS.account_id,
29 | AGS.account_name,
30 | AGS.campaign_id,
31 | AGS.campaign_name,
32 | AGS.asset_group_id,
33 | AGS.asset_group_name,
34 | AGS.asset_group_status,
35 | AGS.ad_strength,
36 | AGS.clicks,
37 | AGS.impressions,
38 | AGS.ctr,
39 | AGS.cost / 1e6 AS cost,
40 | AGS.conversions,
41 | AGS.all_conversions,
42 | AGS.conversions_value,
43 | AGS.all_conversions_value,
44 | AGS.value_per_all_conversions,
45 | AGS.value_per_conversion,
46 | IFNULL(LA.sum_of_low_perf_assets, 0) AS sum_of_low_performing_assets
47 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
48 | LEFT JOIN LOW_ASSETS AS LA
49 | ON AGS.asset_group_id = LA.asset_group_id
50 | )
--------------------------------------------------------------------------------
/plugins/retail/bq_queries/16-shopping_campaignproducttype.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.shopping_campaignproducttype` AS (
16 | SELECT
17 | date,
18 | account_id,
19 | account_name,
20 | campaign_name,
21 | campaign_id,
22 | CASE
23 | WHEN product_type_l1 IS NOT NULL AND product_type_l1 <> '' THEN
24 | COALESCE(product_type_l1, '') || CASE WHEN product_type_l2 IS NOT NULL AND product_type_l2 <> '' THEN ' > ' ELSE '' END ||
25 | COALESCE(product_type_l2, '') || CASE WHEN product_type_l3 IS NOT NULL AND product_type_l3 <> '' THEN ' > ' ELSE '' END ||
26 | COALESCE(product_type_l3, '') || CASE WHEN product_type_l4 IS NOT NULL AND product_type_l4 <> '' THEN ' > ' ELSE '' END ||
27 | COALESCE(product_type_l4, '') || CASE WHEN product_type_l5 IS NOT NULL AND product_type_l5 <> '' THEN ' > ' ELSE '' END ||
28 | COALESCE(product_type_l5, '')
29 | ELSE ''
30 | END AS product_type,
31 | SUM(clicks) AS clicks,
32 | SUM(conversions) AS conversions,
33 | SUM(impressions) AS impressions,
34 | SUM(conversions_value) AS sum_conversions_value,
35 | SUM(cost/1e6) AS sum_cost,
36 | SUM(ctr) AS ctr
37 | FROM
38 | `{bq_dataset}.shoppingperformance_view`
39 | GROUP BY 1,2,3,4,5,6
40 | )
41 |
--------------------------------------------------------------------------------
/bq_queries/08-assetsummary.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.summaryassets` AS (
16 | SELECT
17 | AGA.account_id,
18 | AGA.account_name,
19 | AGA.asset_group_id,
20 | AGA.asset_group_name,
21 | AGA.campaign_name,
22 | AGA.campaign_id,
23 | AGA.asset_id,
24 | AGA.asset_sub_type,
25 | AGA.asset_performance,
26 | AGA.text_asset_text,
27 | AGS.asset_group_status,
28 | COALESCE(AGA.image_url,CONCAT('https://www.youtube.com/watch?v=',AGA.video_id)) AS image_video,
29 | COALESCE(AGA.image_url,CONCAT('https://i.ytimg.com/vi/', CONCAT(AGA.video_id, '/hqdefault.jpg'))) AS image_video_url,
30 | OCID.ocid,
31 | CS.last_30_day_campaign_cost
32 | FROM `{bq_dataset}.assetgroupasset` AS AGA
33 | JOIN `{bq_dataset}.assetgroupsummary` AS AGS
34 | USING(asset_group_id)
35 | LEFT JOIN `{bq_dataset}.ocid_mapping` AS OCID
36 | ON OCID.customer_id = AGA.account_id
37 | LEFT JOIN (
38 | SELECT
39 | campaign_id,
40 | SUM(cost) AS last_30_day_campaign_cost
41 | FROM `{bq_dataset}.campaign_settings`
42 | WHERE PARSE_DATE('%Y-%m-%d', date) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
43 | GROUP BY campaign_id
44 | ) AS CS ON AGA.campaign_id = CS.campaign_id
45 | WHERE AGA.asset_performance NOT IN ('PENDING','UNKNOWN')
46 | AND AGA.campaign_id
47 | IN (SELECT campaign_id FROM `{bq_dataset}.campaign_settings`)
48 | GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
49 |
--------------------------------------------------------------------------------
/google_ads_queries/campaignconversionaction.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | SELECT
17 | campaign.id as campaign_id,
18 | campaign.name as campaign_name,
19 | campaign.status as campaign_status,
20 | campaign.advertising_channel_type as campaign_type,
21 | customer.id as account_id,
22 | customer.descriptive_name as account_name,
23 | segments.conversion_action_category as conversion_action_category,
24 | segments.conversion_action as conversion_action_id,
25 | segments.conversion_action_name as conversion_action_name,
26 | segments.date as date,
27 | metrics.all_conversions as all_conversions,
28 | metrics.all_conversions_by_conversion_date as all_conversions_by_conversion_date,
29 | metrics.all_conversions_value as all_conversions_value,
30 | metrics.all_conversions_value_by_conversion_date as all_conversions_value_by_conversion_date,
31 | metrics.conversions as conversions,
32 | metrics.conversions_by_conversion_date as conversions_by_conversion_date,
33 | metrics.conversions_value as conversions_value,
34 | metrics.conversions_value_by_conversion_date as conversions_value_by_conversion_date,
35 | metrics.value_per_conversion as value_per_conversion,
36 | metrics.value_per_all_conversions as value_per_all_conversions,
37 | metrics.view_through_conversions as view_through_conversions
38 | FROM campaign
39 | WHERE campaign.advertising_channel_type = "PERFORMANCE_MAX"
40 | AND segments.date >= "{start_date}"
41 | AND segments.date <= "{end_date}"
42 | AND campaign.status = 'ENABLED'
--------------------------------------------------------------------------------
/google_ads_queries/campaign_settings.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | SELECT
16 | segments.date AS date,
17 | customer.id AS account_id,
18 | customer.descriptive_name AS account_name,
19 | campaign.id AS campaign_id,
20 | campaign.name AS campaign_name,
21 | campaign.status AS campaign_status,
22 | campaign.url_expansion_opt_out AS url_expansion_opt_out,
23 | campaign.bidding_strategy_type AS bidding_strategy,
24 | campaign_budget.amount_micros AS budget_amount,
25 | campaign_budget.total_amount_micros AS total_budget,
26 | campaign_budget.type AS budget_type,
27 | campaign_budget.explicitly_shared AS is_shared_budget,
28 | campaign_budget.period AS budget_period,
29 | bidding_strategy.maximize_conversion_value.target_roas AS bidding_strategy_mcv_troas,
30 | bidding_strategy.target_roas.target_roas AS bidding_strategy_troas,
31 | bidding_strategy.maximize_conversions.target_cpa_micros AS bidding_strategy_mc_tcpa,
32 | bidding_strategy.target_cpa.target_cpa_micros AS bidding_strategy_tcpa,
33 | campaign.maximize_conversions.target_cpa_micros AS campaign_mc_tcpa,
34 | campaign.target_cpa.target_cpa_micros AS campaign_tcpa,
35 | campaign.maximize_conversion_value.target_roas AS campaign_mcv_troas,
36 | campaign.target_roas.target_roas AS campaign_troas,
37 | campaign.selective_optimization.conversion_actions AS selective_optimization_conversion_actions,
38 | campaign.shopping_setting.merchant_id as gmc_id,
39 | campaign.optimization_score as optiscore,
40 | campaign.geo_target_type_setting.negative_geo_target_type as negative_geo_target_type,
41 | campaign.geo_target_type_setting.positive_geo_target_type as positive_geo_target_type,
42 | metrics.cost_micros AS cost,
43 | metrics.conversions AS conversions,
44 | metrics.conversions_value AS conversions_value,
45 | metrics.all_conversions_value AS all_conversions_value
46 | FROM campaign
47 | WHERE campaign.advertising_channel_type = "PERFORMANCE_MAX"
48 | AND segments.date >= "{start_date}"
49 | AND segments.date <= "{end_date}"
50 | AND campaign.status = 'ENABLED'
--------------------------------------------------------------------------------
/bq_queries/03-primary_conversion_action_search.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.primary_conversion_action_search`
16 | AS
17 | WITH CONVERSION_ACCOUNT_LEVEL AS (
18 | SELECT DISTINCT
19 | account_id,
20 | campaign_id,
21 | campaign_type,
22 | conversion_name
23 | FROM `{bq_dataset}.conversion_category`
24 | ),
25 | CONVERSION_SPLIT AS (
26 | SELECT
27 | account_id,
28 | campaign_id,
29 | campaign_type,
30 | ARRAY_TO_STRING(ARRAY_AGG(conversion_name),",") AS conversion_name
31 | FROM CONVERSION_ACCOUNT_LEVEL
32 | GROUP BY 1,2,3
33 | UNION ALL
34 | SELECT
35 | account_id,
36 | campaign_id,
37 | campaign_type,
38 | custom_conversion_goal_name AS conversion_name
39 | FROM `{bq_dataset}.conversion_custom`
40 | JOIN `{bq_dataset}.custom_goal_names`
41 | USING (account_id,custom_conversion_goal_id)
42 | ),
43 | CONVERSION_SPLIT_GROUPED_W_CUSTOM AS (
44 | SELECT
45 | account_id,
46 | campaign_id,
47 | campaign_type,
48 | ARRAY_TO_STRING(ARRAY_AGG(conversion_name),",") AS conversion_name
49 | FROM CONVERSION_SPLIT
50 | GROUP BY 1,2,3
51 | ),
52 | CONVERSION_ACTION_FREQUENCY AS (
53 | SELECT
54 | account_id,
55 | campaign_type,
56 | conversion_name,
57 | RANK() OVER (PARTITION BY account_id, campaign_type
58 | ORDER BY COUNT(DISTINCT campaign_id) DESC) AS row_num
59 | FROM CONVERSION_SPLIT_GROUPED_W_CUSTOM
60 | WHERE campaign_type = "SEARCH"
61 | GROUP BY
62 | account_id,
63 | conversion_name,
64 | campaign_type
65 | ),
66 | CONVERSION_ACTION_FREQUENCY_GROUPED AS (
67 | SELECT DISTINCT
68 | account_id,
69 | campaign_type,
70 | row_num,
71 | conversion_name
72 | FROM CONVERSION_ACTION_FREQUENCY
73 | ),
74 | MOST_USED_CONVERSIONS AS (
75 | SELECT DISTINCT
76 | CS.account_id,
77 | CS.campaign_id,
78 | CF.conversion_name
79 | FROM CONVERSION_SPLIT_GROUPED_W_CUSTOM CS
80 | JOIN CONVERSION_ACTION_FREQUENCY_GROUPED CF
81 | USING (account_id)
82 | WHERE row_num = 1
83 | AND CS.campaign_type = "SEARCH"
84 | )
85 | SELECT DISTINCT
86 | account_id,
87 | conversion_name
88 | FROM MOST_USED_CONVERSIONS
--------------------------------------------------------------------------------
/plugins/retail/bq_queries/18-shopping_lowclicks_highroas_producttype.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.shopping_lowclicks_highroas_producttype` AS (
16 | WITH no_date_shopping_gads AS (
17 | SELECT
18 | campaign_name,
19 | campaign_id,
20 | CASE
21 | WHEN product_type_l1 IS NOT NULL AND product_type_l1 <> '' THEN
22 | COALESCE(product_type_l1, '') || CASE WHEN product_type_l2 IS NOT NULL AND product_type_l2 <> '' THEN ' > ' ELSE '' END ||
23 | COALESCE(product_type_l2, '') || CASE WHEN product_type_l3 IS NOT NULL AND product_type_l3 <> '' THEN ' > ' ELSE '' END ||
24 | COALESCE(product_type_l3, '') || CASE WHEN product_type_l4 IS NOT NULL AND product_type_l4 <> '' THEN ' > ' ELSE '' END ||
25 | COALESCE(product_type_l4, '') || CASE WHEN product_type_l5 IS NOT NULL AND product_type_l5 <> '' THEN ' > ' ELSE '' END ||
26 | COALESCE(product_type_l5, '')
27 | ELSE ''
28 | END AS product_type,
29 | SUM(clicks) AS clicks,
30 | SUM(conversions) AS conversions,
31 | SUM(impressions) AS impressions,
32 | SUM(conversions_value) AS conversions_value,
33 | SUM(cost/1e6) AS cost,
34 | SUM(ctr) AS ctr
35 | FROM
36 | `{bq_dataset}.shoppingperformance_view`
37 | GROUP BY 1,2,3
38 | ),
39 | AverageClicks AS (
40 | SELECT
41 | SUM(clicks) / COUNT(*) AS average_clicks
42 | FROM
43 | no_date_shopping_gads
44 | )
45 | SELECT
46 | NDSG.campaign_name,
47 | NDSG.product_type,
48 | CONCAT(NDSG.product_type, ' ||| ', NDSG.campaign_name) AS product_type_plus_campaign,
49 | AC.average_clicks,
50 | NDSG.clicks,
51 | NDSG.impressions,
52 | NDSG.cost,
53 | NDSG.conversions_value,
54 | CASE
55 | WHEN NDSG.cost = 0 THEN 0
56 | ELSE NDSG.conversions_value/NDSG.cost
57 | END AS roas
58 | FROM
59 | no_date_shopping_gads NDSG,
60 | AverageClicks AC
61 | WHERE
62 | NDSG.clicks BETWEEN 0.10 * AC.average_clicks AND 0.50 * AC.average_clicks
63 | ORDER BY roas DESC
64 | LIMIT 15
65 | )
66 |
--------------------------------------------------------------------------------
/no_gmc_update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2022 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | #This is a script to update the version of the retail pmax that uses the Merchant Center data to the version hat doesn;t use GMC data, only google Ads.
18 | set -e
19 |
20 | git pull
21 |
22 | ANSWERS="answers.json"
23 | WORK_RETAIL="work_retail"
24 |
25 | # Using Node.js to read values from answers.json
26 | READ_SCRIPT="
27 | const fs = require('fs');
28 | const data = JSON.parse(fs.readFileSync('${ANSWERS}', 'utf8'));
29 | console.log(data.name);
30 | console.log(data.gcs_bucket);
31 | console.log(data.path_to_bq_queries);
32 | "
33 |
34 | # Read values from answers.json to determine which bucket to delete.
35 | read -r name gcs_bucket path_to_bq_queries <<< $(node -e "$READ_SCRIPT")
36 |
37 | # Determine the GCS bucket name
38 | if [ -z "$gcs_bucket" ]; then
39 | PROJECT_ID=$(gcloud config get-value project)
40 | BUCKET_NAME=$PROJECT_ID
41 | else
42 | BUCKET_NAME=$gcs_bucket
43 | fi
44 |
45 | # Construct the full path of the folder to delete
46 | FOLDER_PATH="gs://${BUCKET_NAME}/${name}/${path_to_bq_queries}"
47 |
48 | # Check if the folder exists
49 | if gsutil ls "$FOLDER_PATH" >/dev/null 2>&1; then
50 | # Deleting the folder in the GCS bucket
51 | gsutil -m rm -r "${FOLDER_PATH}"
52 | echo "Folder ${path_to_bq_queries} in bucket ${BUCKET_NAME} under ${name} has been deleted."
53 | else
54 | echo "Folder ${path_to_bq_queries} does not exist in bucket ${BUCKET_NAME} under ${name}."
55 | fi
56 |
57 |
58 | if [ -d "$WORK_RETAIL" ]; then
59 | # Check and remove bq_queries if it exists
60 | if [ -d "$WORK_RETAIL/bq_queries" ]; then
61 | rm -rf "$WORK_RETAIL/bq_queries"
62 | echo "Directory '$WORK_RETAIL/bq_queries' has been removed."
63 | else
64 | echo "Directory '$WORK_RETAIL/bq_queries' does not exist."
65 | fi
66 |
67 | # Check and remove google_ads_queries if it exists
68 | if [ -d "$WORK_RETAIL/google_ads_queries" ]; then
69 | rm -rf "$WORK_RETAIL/google_ads_queries"
70 | echo "Directory '$WORK_RETAIL/google_ads_queries' has been removed."
71 | else
72 | echo "Directory '$WORK_RETAIL/google_ads_queries' does not exist."
73 | fi
74 | else
75 | echo "Directory '$WORK_RETAIL' does not exist."
76 | #if the directory doesn't exist at all, we will need to deploy from scratch
77 | ./build-retail.sh
78 | cd "$WORK_RETAIL"
79 | npm init gaarf-wf@latest -- --answers=answers.json
80 | exit
81 | fi
82 | ./build-retail.sh
83 | cd "$WORK_RETAIL"
84 | ./deploy-queries.sh
85 | ./run-wf.sh
--------------------------------------------------------------------------------
/bq_queries/02-primary_conversion_action_pmax.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.primary_conversion_action_pmax` AS
16 | WITH
17 | CONVERSION_ACCOUNT_LEVEL AS (
18 | SELECT DISTINCT
19 | account_id,
20 | campaign_id,
21 | campaign_type,
22 | conversion_name
23 | FROM `{bq_dataset}.conversion_category`
24 | ),
25 | CONVERSION_SPLIT AS (
26 | SELECT
27 | account_id,
28 | campaign_id,
29 | campaign_type,
30 | ARRAY_TO_STRING(ARRAY_AGG(conversion_name),",") AS conversion_name
31 | FROM CONVERSION_ACCOUNT_LEVEL
32 | GROUP BY 1,2,3
33 | UNION ALL
34 | SELECT
35 | account_id,
36 | campaign_id,
37 | campaign_type,
38 | custom_conversion_goal_name AS conversion_name
39 | FROM `{bq_dataset}.conversion_custom`
40 | JOIN `{bq_dataset}.custom_goal_names` USING (account_id,custom_conversion_goal_id)
41 | ),
42 | CONVERSION_SPLIT_GROUPED_W_CUSTOM AS (
43 | SELECT
44 | account_id,
45 | campaign_id,
46 | campaign_type,
47 | ARRAY_TO_STRING(ARRAY_AGG(conversion_name),",") AS conversion_name
48 | FROM CONVERSION_SPLIT
49 | GROUP BY 1,2,3
50 | ),
51 | CONVERSION_ACTION_FREQUENCY AS (
52 | SELECT
53 | account_id,
54 | campaign_id,
55 | campaign_type,
56 | conversion_name,
57 | RANK() OVER (PARTITION BY account_id, campaign_type
58 | ORDER BY COUNT(DISTINCT campaign_id) DESC) AS row_num
59 | FROM CONVERSION_SPLIT_GROUPED_W_CUSTOM
60 | WHERE campaign_type = "PERFORMANCE_MAX"
61 | GROUP BY
62 | account_id,
63 | conversion_name,
64 | campaign_type,
65 | campaign_id
66 | ),
67 | CONVERSION_ACTION_FREQUENCY_GROUPED AS (
68 | SELECT
69 | account_id,
70 | campaign_id,
71 | campaign_type,
72 | row_num,
73 | ARRAY_TO_STRING(ARRAY_AGG(conversion_name),",") AS conversion_name
74 | FROM CONVERSION_ACTION_FREQUENCY
75 | GROUP BY
76 | account_id,
77 | campaign_id,
78 | campaign_type,
79 | row_num
80 | ),
81 | MOST_USED_CONVERSIONS AS (
82 | SELECT
83 | CS.account_id,
84 | CS.campaign_id,
85 | ARRAY_TO_STRING(ARRAY_AGG(CF.conversion_name),",") AS conversion_name
86 | FROM CONVERSION_SPLIT_GROUPED_W_CUSTOM AS CS
87 | JOIN CONVERSION_ACTION_FREQUENCY_GROUPED AS CF
88 | USING (account_id, campaign_id)
89 | WHERE row_num = 1
90 | AND CS.campaign_type = "PERFORMANCE_MAX"
91 | GROUP BY 1,2
92 | )
93 | SELECT DISTINCT
94 | account_id,
95 | campaign_id,
96 | conversion_name
97 | FROM MOST_USED_CONVERSIONS
--------------------------------------------------------------------------------
/bq_queries/04-text_assets.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.text_assets`
16 | AS
17 | WITH count_headlines AS (
18 | SELECT
19 | campaign_id,
20 | asset_group_id,
21 | COUNT(*) AS count_headlines
22 | FROM `{bq_dataset}.assetgroupasset`
23 | WHERE asset_sub_type IN ('HEADLINE', 'LONG_HEADLINE')
24 | GROUP BY 1, 2
25 | ),
26 | count_short_headlines AS (
27 | SELECT
28 | AGA.campaign_id,
29 | AGA.asset_group_id,
30 | COUNT(*) AS count_short_headlines
31 | FROM `{bq_dataset}.assetgroupasset` AS AGA
32 | WHERE AGA.asset_sub_type = 'HEADLINE'
33 | GROUP BY 1, 2
34 | ),
35 | count_long_headlines AS (
36 | SELECT
37 | AGA.campaign_id,
38 | AGA.asset_group_id,
39 | COUNT(*) AS count_long_headlines
40 | FROM `{bq_dataset}.assetgroupasset` AS AGA
41 | WHERE AGA.asset_sub_type = 'LONG_HEADLINE'
42 | GROUP BY 1, 2
43 | ),
44 | count_descriptions AS (
45 | SELECT
46 | AGA.campaign_id,
47 | AGA.asset_group_id,
48 | COUNT(*) AS count_descriptions
49 | FROM `{bq_dataset}.assetgroupasset` AS AGA
50 | WHERE AGA.asset_sub_type = 'DESCRIPTION'
51 | GROUP BY 1, 2
52 | ),
53 | count_short_descriptions AS (
54 | SELECT
55 | AGA.campaign_id,
56 | AGA.asset_group_id,
57 | COUNT(*) AS count_short_descriptions
58 | FROM `{bq_dataset}.assetgroupasset` AS AGA
59 | WHERE AGA.asset_sub_type = 'DESCRIPTION'
60 | AND LENGTH(AGA.text_asset_text) <= 60
61 | GROUP BY 1, 2
62 | )
63 | SELECT DISTINCT
64 | AGS.account_id,
65 | AGS.account_name,
66 | AGS.campaign_id,
67 | AGS.campaign_name,
68 | AGS.asset_group_id,
69 | AGS.asset_group_name,
70 | COALESCE(CH.count_headlines,0) AS count_headlines,
71 | COALESCE(CSH.count_short_headlines,0) AS count_short_headlines,
72 | COALESCE(CD.count_descriptions,0) AS count_descriptions,
73 | COALESCE(CSD.count_short_descriptions,0) AS count_short_descriptions,
74 | COALESCE(CLH.count_long_headlines,0) AS count_long_headlines
75 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
76 | LEFT JOIN count_headlines AS CH
77 | ON CH.campaign_id = AGS.campaign_id
78 | AND CH.asset_group_id = AGS.asset_group_id
79 | LEFT JOIN count_short_headlines AS CSH
80 | ON CSH.campaign_id = AGS.campaign_id
81 | AND CSH.asset_group_id = AGS.asset_group_id
82 | LEFT JOIN count_descriptions AS CD
83 | ON CD.campaign_id = AGS.campaign_id
84 | AND CD.asset_group_id = AGS.asset_group_id
85 | LEFT JOIN count_short_descriptions AS CSD
86 | ON CSD.campaign_id = AGS.campaign_id
87 | AND CSD.asset_group_id = AGS.asset_group_id
88 | LEFT JOIN count_long_headlines AS CLH
89 | ON CLH.campaign_id = AGS.campaign_id
90 | AND CLH.asset_group_id = AGS.asset_group_id
91 | GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
92 |
--------------------------------------------------------------------------------
/bq_queries/12-campaign_settings.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.campaign_settings` AS
16 | WITH
17 | TARGETS AS (
18 | SELECT
19 | C.date,
20 | C.account_id,
21 | C.campaign_id,
22 | CASE
23 | WHEN C.campaign_mcv_troas IS NOT NULL THEN C.campaign_mcv_troas
24 | WHEN C.campaign_troas IS NOT NULL THEN C.campaign_troas
25 | WHEN C.bidding_strategy_mcv_troas IS NOT NULL THEN C.bidding_strategy_mcv_troas
26 | WHEN C.bidding_strategy_troas IS NOT NULL THEN C.bidding_strategy_troas
27 | END AS troas,
28 | CASE
29 | WHEN C.campaign_mc_tcpa IS NOT NULL THEN C.campaign_mc_tcpa
30 | WHEN C.campaign_tcpa IS NOT NULL THEN C.campaign_tcpa
31 | WHEN C.bidding_strategy_mc_tcpa IS NOT NULL THEN C.bidding_strategy_mc_tcpa
32 | WHEN C.bidding_strategy_tcpa IS NOT NULL THEN C.bidding_strategy_tcpa
33 | END AS tcpa
34 | FROM `{bq_dataset}.campaign_settings` C
35 | ),
36 | ASSET_GROUP_BEST_PRACTICES AS (
37 | SELECT
38 | CAST(DATE(TIMESTAMP(CONCAT(SUBSTR(_TABLE_SUFFIX,0,4),'-',SUBSTR(_TABLE_SUFFIX,5,2),'-',SUBSTR(_TABLE_SUFFIX,7))))-1 AS STRING) AS date_,
39 | account_id,
40 | campaign_id,
41 | ROUND(AVG(video_score), 2) AS video_score,
42 | ROUND(AVG(text_score), 2) AS text_score,
43 | ROUND(AVG(image_score), 2) AS image_score
44 | FROM `{bq_dataset}_bq.assetgroupbpscore_*`
45 | GROUP BY 1,2,3
46 | ),
47 | CAMPAIGN_BEST_PRACTICES AS (
48 | SELECT
49 | CAST(DATE(TIMESTAMP(CONCAT(SUBSTR(_TABLE_SUFFIX,0,4),'-',SUBSTR(_TABLE_SUFFIX,5,2),'-',SUBSTR(_TABLE_SUFFIX,7))))-1 AS STRING) AS date_,
50 | account_id,
51 | campaign_id,
52 | campaign_bp_score
53 | FROM `{bq_dataset}_bq.campaignbpscore_*`
54 | GROUP BY 1,2,3,4
55 | )
56 | SELECT
57 | C.date,
58 | C.account_id,
59 | C.account_name,
60 | C.campaign_id,
61 | C.campaign_name,
62 | C.bidding_strategy,
63 | C.budget_amount,
64 | C.total_budget,
65 | C.budget_type,
66 | C.is_shared_budget,
67 | C.budget_period,
68 | T.troas,
69 | T.tcpa,
70 | C.gmc_id,
71 | C.optiscore,
72 | C.cost/1e6 AS cost,
73 | C.conversions,
74 | C.conversions_value,
75 | C.all_conversions_value,
76 | ABP.video_score,
77 | ABP.text_score,
78 | ABP.image_score,
79 | CBP.campaign_bp_score,
80 | OCID.ocid
81 | FROM `{bq_dataset}.campaign_settings` AS C
82 | LEFT JOIN TARGETS AS T
83 | USING(account_id, campaign_id, date)
84 | LEFT JOIN ASSET_GROUP_BEST_PRACTICES AS ABP
85 | ON C.date = ABP.date_
86 | AND C.account_id = ABP.account_id
87 | AND C.campaign_id = ABP.campaign_id
88 | LEFT JOIN CAMPAIGN_BEST_PRACTICES AS CBP
89 | ON C.date = CBP.date_
90 | AND C.account_id = CBP.account_id
91 | AND C.campaign_id = CBP.campaign_id
92 | LEFT JOIN `{bq_dataset}.ocid_mapping` AS OCID
93 | ON OCID.customer_id = C.account_id;
94 |
--------------------------------------------------------------------------------
/bq_queries/01-image_assets.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE SCHEMA IF NOT EXISTS `{bq_dataset}_bq`;
16 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.image_assets`
17 | AS
18 | WITH count_image_assets AS (
19 | SELECT
20 | campaign_id,
21 | asset_group_id,
22 | COUNT(*) AS count_images
23 | FROM
24 | `{bq_dataset}.assetgroupasset`
25 | WHERE asset_type = 'IMAGE'
26 | GROUP BY 1, 2
27 | ),
28 | count_logos AS (
29 | SELECT
30 | campaign_id,
31 | asset_group_id,
32 | COUNT(*) AS count_logos
33 | FROM
34 | `{bq_dataset}.assetgroupasset`
35 | WHERE asset_sub_type = 'LOGO'
36 | GROUP BY 1, 2
37 | ),
38 | count_landscape_assets AS (
39 | SELECT
40 | campaign_id,
41 | asset_group_id,
42 | COUNT(*) AS count_landscape
43 | FROM
44 | `{bq_dataset}.assetgroupasset`
45 | WHERE asset_sub_type = 'MARKETING_IMAGE'
46 | GROUP BY 1, 2
47 | ),
48 | count_portrait_assets AS (
49 | SELECT
50 | campaign_id,
51 | asset_group_id,
52 | COUNT(*) AS count_portrait
53 | FROM
54 | `{bq_dataset}.assetgroupasset`
55 | WHERE asset_sub_type = 'PORTRAIT_MARKETING_IMAGE'
56 | GROUP BY 1, 2
57 | ),
58 | count_square_images AS (
59 | SELECT
60 | campaign_id,
61 | asset_group_id,
62 | COUNT(*) AS count_square
63 | FROM `{bq_dataset}.assetgroupasset`
64 | WHERE asset_sub_type = 'SQUARE_MARKETING_IMAGE'
65 | GROUP BY 1, 2
66 | ),
67 | count_square_logos AS (
68 | SELECT
69 | campaign_id,
70 | asset_group_id,
71 | COUNT(*) AS count_square_logos
72 | FROM `{bq_dataset}.assetgroupasset`
73 | WHERE image_width = image_height
74 | AND asset_sub_type = 'LOGO'
75 | GROUP BY 1, 2
76 | ),
77 | count_landscape_logos AS (
78 | SELECT
79 | campaign_id,
80 | asset_group_id,
81 | COUNT(*) AS count_landscape_logos
82 | FROM `{bq_dataset}.assetgroupasset`
83 | WHERE ROUND(SAFE_DIVIDE(image_width, image_height),2) = 4
84 | AND asset_sub_type = 'LOGO'
85 | GROUP BY 1, 2
86 | )
87 | SELECT DISTINCT
88 | AGS.account_id,
89 | AGS.account_name,
90 | AGS.campaign_id,
91 | AGS.campaign_name,
92 | AGS.asset_group_id,
93 | AGS.asset_group_name,
94 | COALESCE(CIA.count_images,0) AS count_images,
95 | COALESCE(CL.count_logos,0) AS count_logos,
96 | COALESCE(CLA.count_landscape,0) AS count_landscape,
97 | COALESCE(CSN.count_square,0) AS count_square,
98 | COALESCE(CPA.count_portrait,0) AS count_portrait,
99 | COALESCE(CSL.count_square_logos,0) AS count_square_logos,
100 | COALESCE(CRL.count_landscape_logos,0) AS count_landscape_logos,
101 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
102 | LEFT JOIN count_image_assets AS CIA
103 | ON CIA.campaign_id = AGS.campaign_id
104 | AND CIA.asset_group_id = AGS.asset_group_id
105 | LEFT JOIN count_logos AS CL
106 | ON CL.campaign_id = AGS.campaign_id
107 | AND CL.asset_group_id = AGS.asset_group_id
108 | LEFT JOIN count_landscape_assets AS CLA
109 | ON CLA.campaign_id = AGS.campaign_id
110 | AND CLA.asset_group_id = AGS.asset_group_id
111 | LEFT JOIN count_square_images AS CSN
112 | ON CSN.campaign_id = AGS.campaign_id
113 | AND CSN.asset_group_id = AGS.asset_group_id
114 | LEFT JOIN count_portrait_assets AS CPA
115 | ON CPA.campaign_id = AGS.campaign_id
116 | AND CPA.asset_group_id = AGS.asset_group_id
117 | LEFT JOIN count_square_logos AS CSL
118 | ON CSL.campaign_id = AGS.campaign_id
119 | AND CSL.asset_group_id = AGS.asset_group_id
120 | LEFT JOIN count_landscape_logos AS CRL
121 | ON CRL.campaign_id = AGS.campaign_id
122 | AND CRL.asset_group_id = AGS.asset_group_id
123 | GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
124 |
--------------------------------------------------------------------------------
/bq_queries/11-assetgroupbestpracticessnapshots.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.assetgroupbpscore_${format(today(),'yyyyMMdd')}` AS
16 | WITH video_data AS (
17 | SELECT
18 | account_id,
19 | account_name,
20 | campaign_id,
21 | campaign_name,
22 | asset_group_id,
23 | asset_group_name,
24 | ad_strength,
25 | is_video_uploaded,
26 | count_videos,
27 | IF(count_videos < 3, CAST(0 AS FLOAT64), CAST(1 as FLOAT64)) AS video_score
28 | FROM `{bq_dataset}_bq.video_assets`
29 | ),
30 | text_data AS (
31 | SELECT
32 | account_id,
33 | account_name,
34 | campaign_id,
35 | campaign_name,
36 | asset_group_id,
37 | count_descriptions,
38 | count_headlines,
39 | count_long_headlines,
40 | count_short_descriptions,
41 | count_short_headlines,
42 | (IF(count_descriptions >= 4, 1, 0) +
43 | IF(count_headlines >= 11, 1, 0) +
44 | IF(count_long_headlines >= 2, 1, 0)) / 3 AS text_score
45 | FROM `{bq_dataset}_bq.text_assets`
46 | ),
47 | image_data AS (
48 | SELECT
49 | account_id,
50 | account_name,
51 | campaign_id,
52 | campaign_name,
53 | asset_group_id,
54 | count_images,
55 | count_logos,
56 | count_landscape,
57 | count_portrait,
58 | count_landscape_logos,
59 | count_square,
60 | count_square_logos,
61 | (IF(count_landscape >= 4, 1, 0) +
62 | IF(count_square >= 4, 1, 0) +
63 | IF(count_portrait >= 4, 1, 0) +
64 | IF(count_landscape_logos >= 1, 1, 0) +
65 | IF(count_square_logos >= 1, 1, 0)) / 5 AS image_score
66 | FROM `{bq_dataset}_bq.image_assets`
67 | ),
68 | audience_signals_count AS (
69 | SELECT
70 | AGS.campaign_id AS campaign_id,
71 | AGS.asset_group_id,
72 | COUNT(DISTINCT AGS.asset_group_id) AS number_of_audience_signals,
73 | FROM `{bq_dataset}.assetgroupsignal` AGS
74 | GROUP BY
75 | campaign_id,
76 | asset_group_id
77 | )
78 | SELECT
79 | CURRENT_DATE() AS date,
80 | AGS.account_id,
81 | AGS.account_name,
82 | AGS.campaign_id,
83 | AGS.campaign_name,
84 | AGS.asset_group_id,
85 | AGS.asset_group_name,
86 | AGS.ad_strength,
87 | V.is_video_uploaded,
88 | V.video_score,
89 | T.text_score,
90 | I.image_score,
91 | IF(T.count_descriptions < 4, 4 - T.count_descriptions, 0) AS missing_descriptions,
92 | IF(T.count_descriptions < 5, 5 - T.count_descriptions, 0) AS missing_descriptions_max,
93 | IF(T.count_headlines < 11, 11 - T.count_headlines, 0) AS missing_headlines,
94 | IF(T.count_headlines < 15, 15 - T.count_headlines, 0) AS missing_headlines_max,
95 | IF(T.count_long_headlines < 2, 2 - T.count_long_headlines, 0) AS missing_long_headlines,
96 | IF(T.count_long_headlines < 5, 5 - T.count_long_headlines, 0) AS missing_long_headlines_max,
97 | IF((I.count_landscape + I.count_square + I.count_portrait + I.count_logos) < 12, 12 - (I.count_landscape + I.count_square + I.count_portrait + I.count_logos), 0) AS missing_images,
98 | IF((I.count_landscape + I.count_square + I.count_portrait + I.count_logos) < 20, 20 - (I.count_landscape + I.count_square + I.count_portrait + I.count_logos), 0) AS missing_images_max,
99 | IF(I.count_landscape < 4, 4 - I.count_landscape, 0) AS missing_landscape,
100 | IF(I.count_square < 4, 4 - I.count_square, 0) AS missing_square,
101 | IF(I.count_portrait < 2, 2 - I.count_portrait, 0) AS missing_portrait,
102 | IF(I.count_logos < 2, 2 - I.count_logos, 0) AS missing_logos,
103 | IF(I.count_square_logos = 0, 1, 0) AS missing_square_logos,
104 | IF(I.count_landscape_logos = 0, 1, 0) AS missing_landscape_logos,
105 | IF(V.count_videos < 3, 3 - V.count_videos, 0) AS missing_video,
106 | IF(V.count_videos < 5, 5 - V.count_videos, 0) AS missing_video_max,
107 | IF(ASA.number_of_audience_signals IS NOT NULL,"Yes","X") AS audience_signals
108 | FROM `{bq_dataset}.assetgroupsummary` AGS
109 | INNER JOIN video_data AS V
110 | ON AGS.account_id = V.account_id
111 | AND AGS.campaign_id = V.campaign_id
112 | AND AGS.asset_group_id = V.asset_group_id
113 | INNER JOIN text_data AS T
114 | ON AGS.account_id = T.account_id
115 | AND AGS.campaign_id = T.campaign_id
116 | AND AGS.asset_group_id = T.asset_group_id
117 | INNER JOIN image_data AS I
118 | ON AGS.account_id = I.account_id
119 | AND AGS.campaign_id = I.campaign_id
120 | AND AGS.asset_group_id = I.asset_group_id
121 | LEFT JOIN audience_signals_count AS ASA
122 | ON AGS.campaign_id = ASA.campaign_id
123 | AND AGS.asset_group_id = ASA.asset_group_id
124 | WHERE AGS.campaign_id IN (SELECT campaign_id FROM `{bq_dataset}.campaign_settings`)
--------------------------------------------------------------------------------
/bq_queries/10-assetgroupbestpractices.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.assetgroupbestpractices` AS
16 | WITH
17 | VIDEO_DATA AS (
18 | SELECT
19 | account_id,
20 | account_name,
21 | campaign_id,
22 | campaign_name,
23 | asset_group_id,
24 | asset_group_name,
25 | ad_strength,
26 | is_video_uploaded,
27 | count_videos,
28 | IF(count_videos < 3, CAST(0 AS FLOAT64), CAST(1 as FLOAT64)) AS video_score
29 | FROM `{bq_dataset}_bq.video_assets`
30 | ),
31 | TEXT_DATA AS (
32 | SELECT
33 | account_id,
34 | account_name,
35 | campaign_id,
36 | campaign_name,
37 | asset_group_id,
38 | count_descriptions,
39 | count_headlines,
40 | count_long_headlines,
41 | count_short_descriptions,
42 | count_short_headlines,
43 | (IF(count_descriptions >= 4, 1, 0) +
44 | IF(count_headlines >= 11, 1, 0) +
45 | IF(count_long_headlines >= 2, 1, 0)) / 3 AS text_score
46 | FROM `{bq_dataset}_bq.text_assets`
47 | ),
48 | IMAGE_DATA AS (
49 | SELECT
50 | account_id,
51 | account_name,
52 | campaign_id,
53 | campaign_name,
54 | asset_group_id,
55 | count_images,
56 | count_logos,
57 | count_landscape,
58 | count_portrait,
59 | count_landscape_logos,
60 | count_square,
61 | count_square_logos,
62 | (IF(count_landscape >= 4, 1, 0) +
63 | IF(count_square >= 4, 1, 0) +
64 | IF(count_portrait >= 4, 1, 0) +
65 | IF(count_landscape_logos >= 1, 1, 0) +
66 | IF(count_square_logos >= 1, 1, 0)) / 5 AS image_score
67 | FROM `{bq_dataset}_bq.image_assets`
68 | ),
69 | AUDIENCE_SIGNALS_COUNT AS (
70 | SELECT
71 | COUNT(DISTINCT AGS.asset_group_id) AS number_of_audience_signals,
72 | AGS.campaign_id AS campaign_id,
73 | AGS.asset_group_id
74 | FROM `{bq_dataset}.assetgroupsignal` AS AGS
75 | GROUP BY
76 | campaign_id,
77 | asset_group_id
78 | )
79 | SELECT
80 | AGS.date,
81 | AGS.account_id,
82 | AGS.account_name,
83 | AGS.campaign_id,
84 | AGS.campaign_name,
85 | AGS.asset_group_id,
86 | AGS.asset_group_name,
87 | AGS.ad_strength,
88 | V.is_video_uploaded,
89 | V.video_score,
90 | T.text_score,
91 | I.image_score,
92 | "Recommended" AS recommendation_type,
93 | IF(T.count_descriptions < 4, 4 - T.count_descriptions, 0) AS missing_descriptions,
94 | IF(T.count_headlines < 11, 11 - T.count_headlines, 0) AS missing_headlines,
95 | IF(T.count_long_headlines < 2, 2 - T.count_long_headlines, 0) AS missing_long_headlines,
96 | IF((I.count_landscape + I.count_square + I.count_portrait + I.count_logos) < 12,
97 | 12 - (I.count_landscape + I.count_square + I.count_portrait + I.count_logos), 0) AS missing_images,
98 | IF(I.count_landscape < 4, 4 - I.count_landscape, 0) AS missing_landscape,
99 | IF(I.count_square < 4, 4 - I.count_square, 0) AS missing_square,
100 | IF(I.count_portrait < 2, 2 - I.count_portrait, 0) AS missing_portrait,
101 | IF(I.count_logos < 2, 2 - I.count_logos, 0) AS missing_logos,
102 | IF(I.count_square_logos = 0, 1, 0) AS missing_square_logos,
103 | IF(I.count_landscape_logos = 0, 1, 0) AS missing_landscape_logos,
104 | IF(V.count_videos < 3, 3 - V.count_videos, 0) AS missing_video,
105 | IF(ASA.number_of_audience_signals IS NOT NULL,"Yes","X") AS audience_signals,
106 | OCID.ocid
107 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
108 | INNER JOIN VIDEO_DATA AS V
109 | ON AGS.account_id = V.account_id
110 | AND AGS.campaign_id = V.campaign_id
111 | AND AGS.asset_group_id = V.asset_group_id
112 | INNER JOIN TEXT_DATA AS T
113 | ON AGS.account_id = T.account_id
114 | AND AGS.campaign_id = T.campaign_id
115 | AND AGS.asset_group_id = T.asset_group_id
116 | INNER JOIN IMAGE_DATA AS I
117 | ON AGS.account_id = I.account_id
118 | AND AGS.campaign_id = I.campaign_id
119 | AND AGS.asset_group_id = I.asset_group_id
120 | LEFT JOIN AUDIENCE_SIGNALS_COUNT AS ASA
121 | ON AGS.campaign_id = ASA.campaign_id
122 | AND AGS.asset_group_id = ASA.asset_group_id
123 | LEFT JOIN `{bq_dataset}.ocid_mapping` AS OCID
124 | ON OCID.customer_id = AGS.account_id
125 | WHERE AGS.campaign_id IN (SELECT campaign_id FROM `{bq_dataset}.campaign_settings`)
126 | UNION ALL
127 | SELECT
128 | AGS.date,
129 | AGS.account_id,
130 | AGS.account_name,
131 | AGS.campaign_id,
132 | AGS.campaign_name,
133 | AGS.asset_group_id,
134 | AGS.asset_group_name,
135 | AGS.ad_strength,
136 | V.is_video_uploaded,
137 | V.video_score,
138 | T.text_score,
139 | I.image_score,
140 | "Maximum" AS recommendation_type,
141 | IF(T.count_descriptions < 5, 5 - T.count_descriptions, 0) AS missing_descriptions,
142 | IF(T.count_headlines < 15, 15 - T.count_headlines, 0) AS missing_headlines,
143 | IF(T.count_long_headlines < 5, 5 - T.count_long_headlines, 0) AS missing_long_headlines,
144 | IF((I.count_landscape + I.count_square + I.count_portrait + I.count_logos) < 20,
145 | 20 - (I.count_landscape + I.count_square + I.count_portrait + I.count_logos), 0) AS missing_images,
146 | IF(I.count_landscape < 4, 4 - I.count_landscape, 0) AS missing_landscape,
147 | IF(I.count_square < 4, 4 - I.count_square, 0) AS missing_square,
148 | IF(I.count_portrait < 2, 2 - I.count_portrait, 0) AS missing_portrait,
149 | IF(I.count_logos < 2, 2 - I.count_logos, 0) AS missing_logos,
150 | IF(I.count_square_logos = 0, 1, 0) AS missing_square_logos,
151 | IF(I.count_landscape_logos = 0, 1, 0) AS missing_landscape_logos,
152 | IF(V.count_videos < 5, 5 - V.count_videos, 0) AS missing_video,
153 | IF(ASA.number_of_audience_signals IS NOT NULL,"Yes","X") AS audience_signals,
154 | OCID.ocid
155 | FROM `{bq_dataset}.assetgroupsummary` AS AGS
156 | INNER JOIN VIDEO_DATA AS V
157 | ON AGS.account_id = V.account_id
158 | AND AGS.campaign_id = V.campaign_id
159 | AND AGS.asset_group_id = V.asset_group_id
160 | INNER JOIN TEXT_DATA AS T
161 | ON AGS.account_id = T.account_id
162 | AND AGS.campaign_id = T.campaign_id
163 | AND AGS.asset_group_id = T.asset_group_id
164 | INNER JOIN IMAGE_DATA AS I
165 | ON AGS.account_id = I.account_id
166 | AND AGS.campaign_id = I.campaign_id
167 | AND AGS.asset_group_id = I.asset_group_id
168 | LEFT JOIN AUDIENCE_SIGNALS_COUNT AS ASA
169 | ON AGS.campaign_id = ASA.campaign_id
170 | AND AGS.asset_group_id = ASA.asset_group_id
171 | LEFT JOIN `{bq_dataset}.ocid_mapping` AS OCID
172 | ON OCID.customer_id = AGS.account_id
173 | WHERE AGS.campaign_id IN (SELECT campaign_id FROM `{bq_dataset}.campaign_settings`);
--------------------------------------------------------------------------------
/bq_queries/07-campaign_data.sql:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | CREATE OR REPLACE TABLE `{bq_dataset}_bq.campaign_data` AS
16 | WITH
17 | TARGETS_RAW AS (
18 | SELECT
19 | account_id,
20 | campaign_id,
21 | CASE
22 | WHEN campaign_mcv_troas IS NOT NULL THEN campaign_mcv_troas
23 | WHEN campaign_troas IS NOT NULL THEN campaign_troas
24 | WHEN bidding_strategy_mcv_troas IS NOT NULL THEN bidding_strategy_mcv_troas
25 | WHEN bidding_strategy_troas IS NOT NULL THEN bidding_strategy_troas
26 | END AS troas,
27 | CASE
28 | WHEN campaign_mc_tcpa IS NOT NULL THEN campaign_mc_tcpa
29 | WHEN campaign_tcpa IS NOT NULL THEN campaign_tcpa
30 | WHEN bidding_strategy_mc_tcpa IS NOT NULL THEN bidding_strategy_mc_tcpa
31 | WHEN bidding_strategy_tcpa IS NOT NULL THEN bidding_strategy_tcpa
32 | END AS tcpa
33 | FROM `{bq_dataset}.campaign_settings`
34 | ),
35 | TARGETS AS (
36 | SELECT
37 | account_id,
38 | campaign_id,
39 | ANY_VALUE(troas) AS troas,
40 | ANY_VALUE(tcpa) AS tcpa
41 | FROM TARGETS_RAW
42 | GROUP BY 1, 2
43 | ),
44 | ASSET_GROUPS_COUNT AS (
45 | SELECT
46 | COUNT(DISTINCT ASA.asset_group_id) AS number_of_asset_groups,
47 | ASA.campaign_id AS campaign_id
48 | FROM `{bq_dataset}.assetgroupasset` AS ASA
49 | GROUP BY campaign_id
50 | ),
51 | AUDIENCE_SIGNALS_COUNT AS (
52 | SELECT
53 | COUNT(DISTINCT AGS.audience_signals) AS number_of_audience_signals,
54 | AGS.campaign_id AS campaign_id
55 | FROM `{bq_dataset}.assetgroupsignal` AS AGS
56 | GROUP BY
57 | campaign_id
58 | ),
59 | CAMPIAGN_SITELINKS_DATA AS (
60 | SELECT
61 | account_id,
62 | account_name,
63 | campaign_id,
64 | campaign_name,
65 | COUNT(*) AS campaign_sitelinks,
66 | FROM `{bq_dataset}.campaignasset`
67 | WHERE asset_type = 'SITELINK'
68 | GROUP BY 1, 2, 3, 4
69 | ),
70 | ACCOUNT_SITELINKS_DATA AS (
71 | SELECT
72 | account_id,
73 | account_name,
74 | COUNT(*) AS account_sitelinks,
75 | FROM `{bq_dataset}.customerasset`
76 | WHERE asset_type = 'SITELINK'
77 | GROUP BY 1, 2
78 | ),
79 | CAMPAIGN_CALLOUTS_DATA AS (
80 | SELECT
81 | campaign_id,
82 | COUNT(*) AS campaign_callouts
83 | FROM `{bq_dataset}.campaignasset`
84 | WHERE asset_type = 'CALLOUT'
85 | GROUP BY 1
86 | ),
87 | ACCOUNT_CALLOUTS_DATA AS (
88 | SELECT
89 | account_id,
90 | COUNT(*) AS account_callouts
91 | FROM `{bq_dataset}.customerasset`
92 | WHERE asset_type='CALLOUT'
93 | GROUP BY 1
94 | ),
95 | CAMPAIGN_STRUCTURED_SNIPPETS_DATA AS (
96 | SELECT
97 | campaign_id,
98 | COUNT(*) AS campaign_structsnippets
99 | FROM `{bq_dataset}.campaignasset`
100 | WHERE asset_type = 'STRUCTURED_SNIPPET'
101 | GROUP BY 1
102 | ),
103 | ACCOUNT_STRUCTURED_SNIPPETS_DATA AS (
104 | SELECT
105 | account_id,
106 | COUNT(*) AS account_structsnippets
107 | FROM `{bq_dataset}.customerasset`
108 | WHERE asset_type = 'STRUCTURED_SNIPPET'
109 | GROUP BY 1
110 | )
111 | SELECT
112 | C.date,
113 | C.account_id,
114 | C.account_name,
115 | C.campaign_id,
116 | C.campaign_name,
117 | C.campaign_status,
118 | C.url_expansion_opt_out,
119 | C.bidding_strategy,
120 | C.budget_amount,
121 | C.total_budget,
122 | C.budget_type,
123 | C.is_shared_budget,
124 | C.budget_period,
125 | T.troas,
126 | T.tcpa,
127 | C.gmc_id,
128 | C.optiscore,
129 | C.cost/1e6 AS cost,
130 | C.conversions,
131 | C.conversions_value,
132 | PCA.conversion_name AS pmax_conversion,
133 | PCAS.conversion_name AS primary_conversion_search,
134 | C.negative_geo_target_type as negative_geo_target_type,
135 | C.positive_geo_target_type as positive_geo_target_type,
136 | IF (ASCC.number_of_audience_signals IS NOT NULL, ASCC.number_of_audience_signals, 0) AS number_of_audience_signals,
137 | AGC.number_of_asset_groups AS number_of_asset_groups,
138 | IF (C.negative_geo_target_type != 'PRESENCE_OR_INTEREST', "X", "Yes") as negative_geo_target_type_configured_good,
139 | IF (C.positive_geo_target_type != 'PRESENCE_OR_INTEREST', "X", "Yes") as positive_geo_target_type_configured_good,
140 | CASE
141 | WHEN (IF(SD.campaign_sitelinks IS NULL, 0, SD.campaign_sitelinks)
142 | + IF(ASD.account_sitelinks IS NULL, 0, ASD.account_sitelinks)) >= 4
143 | THEN 0
144 | ELSE 4 - (IF(SD.campaign_sitelinks IS NULL, 0, SD.campaign_sitelinks)
145 | + IF(ASD.account_sitelinks IS NULL, 0, ASD.account_sitelinks))
146 | END AS missing_sitelinks,
147 | CASE
148 | WHEN (IF(CD.campaign_callouts IS NULL, 0, CD.campaign_callouts)
149 | + IF(ACD.account_callouts IS NULL, 0, ACD.account_callouts)) >= 1
150 | THEN 0
151 | ELSE 1
152 | END AS missing_callouts,
153 | CASE
154 | WHEN (IF(SSD.campaign_structsnippets IS NULL, 0, SSD.campaign_structsnippets)
155 | + IF(ASSD.account_structsnippets IS NULL, 0, ASSD.account_structsnippets)) >= 1
156 | THEN 0
157 | ELSE 1
158 | END AS missing_structured_snippets,
159 | CASE
160 | WHEN T.tcpa IS NOT NULL AND T.tcpa > 0
161 | THEN 'tCPA'
162 | WHEN T.troas IS NOT NULL AND T.troas > 0
163 | THEN 'tROAS'
164 | ELSE 'null'
165 | END AS target_type,
166 | CASE
167 | WHEN T.tcpa IS NOT NULL AND T.tcpa > 0
168 | THEN T.tcpa
169 | WHEN T.troas IS NOT NULL AND T.troas > 0
170 | THEN T.troas
171 | ELSE NULL
172 | END AS target_value,
173 | CASE
174 | WHEN ASCC.number_of_audience_signals IS NULL
175 | THEN 0
176 | ELSE (ASCC.number_of_audience_signals) / AGC.number_of_asset_groups
177 | END AS audience_signals_score,
178 | OCID.ocid
179 | FROM `{bq_dataset}.campaign_settings` C
180 | LEFT JOIN TARGETS AS T
181 | ON C.account_id = T.account_id
182 | AND C.campaign_id = T.campaign_id
183 | LEFT JOIN `{bq_dataset}_bq.primary_conversion_action_search` AS PCAS
184 | ON C.account_id = PCAS.account_id
185 | LEFT JOIN `{bq_dataset}_bq.primary_conversion_action_pmax` AS PCA
186 | ON PCA.account_id = C.account_id
187 | AND PCA.campaign_id = C.campaign_id
188 | LEFT JOIN ASSET_GROUPS_COUNT AS AGC
189 | ON C.campaign_id = AGC.campaign_id
190 | LEFT JOIN AUDIENCE_SIGNALS_COUNT AS ASCC
191 | ON C.campaign_id = ASCC.campaign_id
192 | LEFT JOIN CAMPIAGN_SITELINKS_DATA AS SD
193 | ON C.campaign_id = SD.campaign_id
194 | LEFT JOIN ACCOUNT_SITELINKS_DATA AS ASD
195 | ON C.account_id = ASD.account_id
196 | LEFT JOIN CAMPAIGN_CALLOUTS_DATA AS CD
197 | ON C.campaign_id = CD.campaign_id
198 | LEFT JOIN ACCOUNT_CALLOUTS_DATA AS ACD
199 | ON C.account_id = ACD.account_id
200 | LEFT JOIN CAMPAIGN_STRUCTURED_SNIPPETS_DATA AS SSD
201 | ON C.campaign_id = SSD.campaign_id
202 | LEFT JOIN ACCOUNT_STRUCTURED_SNIPPETS_DATA AS ASSD
203 | ON C.account_id = ASSD.account_id
204 | LEFT JOIN `{bq_dataset}.ocid_mapping` AS OCID
205 | ON OCID.customer_id = C.account_id;
--------------------------------------------------------------------------------
/walkthrough.md:
--------------------------------------------------------------------------------
1 | # Deploying the pMaximizer
2 |
3 |
4 |
5 |
6 |
7 |
8 | ## Introduction
9 |
10 | In this walkthrough, you'll generate OAuth credentials in preparation for the deployment of pMaximizer.
11 |
12 |
13 |
14 |
15 |
16 | ## Google Cloud Project Setup
17 |
18 | GCP organizes resources into projects. This allows you to
19 | collect all of the related resources for a single application in one place.
20 |
21 | Begin by creating a new project or selecting an existing project for this
22 | dashboard.
23 |
24 |
25 |
26 | For details, see
27 | [Creating a project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
28 |
29 | ### Enable Google Cloud APIs
30 |
31 | Enable the Google Ads API and the BigQuery API so that they're incorporated in the credentials you will generate in the next step.
32 |
33 |
34 |
35 |
36 |
37 | ## Switch Off Ephemeral Mode
38 |
39 | First, let's switch off your shell's ephemeral mode.
40 |
41 | Click **More** and look for the `Ephemeral Mode` option. If it is turned on turn it off. This allows the dashboard code to persist across sessions.
42 |
43 | ## Authorize shell scripts commands
44 |
45 | Copy the following command into the shell, press enter and follow the instructions:
46 | ```bash
47 | cd
48 | git clone https://github.com/google/pmax_best_practices_dashboard.git
49 | cd pmax_best_practices_dashboard
50 | gcloud auth login
51 | ```
52 |
53 |
54 |
55 | ## Configure OAuth Consent Screen
56 |
57 | An authorization token is needed for the dashboard to communicate with Google Ads.
58 |
59 | 1. Go to:
60 | **APIs & Services > OAuth Overview**
61 |
62 | 1. Click on "Get started".
63 |
64 | 1. Under *App information*, enter the **Application name** you want to display.
65 | You can copy the name below and enter it as the application name.
66 |
67 | ```
68 | pMaximizer
69 | ```
70 |
71 | 1. For the **Support email** dropdown menu, select any email address that you have access to.
72 |
73 | 1. In the Next section (Audience):
74 |
75 | * If you have an organization for your application, select **Internal**.
76 | * If you don't have an organization configured for your application,
77 | select **External**.
78 |
79 | 1. Under **Developer contact information**, enter a valid email address and continue to accept the Terms.
80 |
81 | 1. Click
82 | **Create**
83 | to continue.
84 |
85 | Click**Create OAuth client**
86 |
87 | ## Creating OAuth Credentials
88 |
89 | 1. You should land in the following section:
90 | **Clients**
91 |
92 | 1. Under
93 | **Application
94 | type**, select **Web application**.
95 |
96 | 1. Add a
97 | **Name**
98 | for your OAuth client ID.
99 |
100 | 1. Click Authorized redirect URI
101 | and copy the following:
102 | ```
103 | https://developers.google.com/oauthplayground
104 | ```
105 |
106 | 1. Click **Create**. Your OAuth client ID and client secret are generated and
107 | displayed on the OAuth client window.
108 |
109 | 1. Copy the **client_id** and **client_secret** as you will need those in a moment. (if you only see client_id, press OK and then find both id and secret after pressing the "edit" icon)
110 |
111 | ## Add Sensitive Scopes to Consent Screen
112 |
113 | 1. Go to:
114 | **Data Access**
115 |
116 | 1. Click Add or remove scopes
117 | 1. Now in Enter property name or value search for the BigQuery API, check the box for the first option to choose it.
118 | 1. Do the same for Google Ads API.
119 | 1. Click Update
120 |
121 |
122 | ## Generate Refresh Token
123 |
124 | 1. Go to the [OAuth2 Playground](https://developers.google.com/oauthplayground/#step1&scopes=https%3A//www.googleapis.com/auth/adwords&url=https%3A//&content_type=application/json&http_method=GET&useDefaultOauthCred=checked&oauthEndpointSelect=Google&oauthAuthEndpointValue=https%3A//accounts.google.com/o/oauth2/v2/auth&oauthTokenEndpointValue=https%3A//oauth2.googleapis.com/token&includeCredentials=unchecked&accessTokenType=bearer&autoRefreshToken=unchecked&accessType=offline&forceAprovalPrompt=checked&response_type=code) (opens in a new window)
125 | 2. On the right-hand pane, paste the client_id and client_secret in the appropriate fields 
126 | 3. Then on the left hand side of the screen, click the blue **Authorize APIs** button 
127 |
128 | If you are prompted to authorize access, please choose your Google account that has access to Google Ads and approve.
129 |
130 | 5. Now, click the new blue button **Exchange authorization code for tokens** 
131 | 6. Finally, in the middle of the screen you'll see your refresh token on the last line. Copy it and save it for future reference.  *Do not copy the quotation marks*
132 |
133 | ## Join Google Group to access dashboard template
134 |
135 | Use [this link](https://groups.google.com/g/pmax-dashboard-template-readers/) to access the group URL and click on "Join Group"
136 |
137 | 
138 |
139 | ## Deploy Solution
140 |
141 | Run the following command and follow the steps:
142 |
143 | Make sure to have your developer token, your MCC ID and Merchant Center Id(*) on hand, in addition to the rest of the credentials generated in the previous steps.
144 |
145 | (*) if you would like to enhance your analysis for retail use cases.
146 |
147 | When prompted, choose N to enter credentials one by one.
148 |
149 | ```bash
150 | sh setup-wfs.sh
151 | ```
152 |
153 |
154 | ## Conclusion
155 |
156 | Congratulations. You've set up the pMaximizer!
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pMaximizer (Formally pMax Best Practices Dashboard)
2 |
3 | In this README, you'll find:
4 |
5 | - [Problem Statement](#problem-statement)
6 | - [Solution](#solution)
7 | - [Installation](#installation)
8 | - [Prerequisites](#prerequisites)
9 | - [Deliverable (Implementation)](#deliverable-implementation)
10 | - [Architecture](#architecture)
11 | - [Troubleshooting / Q&A](#troubleshooting)
12 | - [Disclaimer](#disclaimer)
13 |
14 | ## Problem Statement
15 |
16 | Reporting for pMax campaigns is cumbersome and advertisers need a simple way to see an overview of their accounts and get a clear picture of their assets's performance in their pmax campaigns.
17 |
18 | ## Solution
19 |
20 | pMaximizer is a best practice dashboard that provides a centralized monitoring of the pMax campaigns' performance and the assets uploaded. Built in Looker Studio, It helps clearly identify if the campaigns and assets comply with the best practice guidelines and gives actionable insights to enhance asset groups' and feed quality.
21 |
22 | Moreover, assets' performance is displayed and conveniently presented so advertisers can refresh poorly performing assets.
23 |
24 | ## Deliverable (Implementation)
25 |
26 | A Looker Studio dashboard based on your Google Ads data. After joining the group below, [click here](https://lookerstudio.google.com/c/reporting/755d5896-5c56-4f5a-9075-79249137c9ea/page/i5YsC) to see it in action.
27 |
28 | [](https://lookerstudio.google.com/c/reporting/755d5896-5c56-4f5a-9075-79249137c9ea/page/i5YsC)
29 |
30 | - LookerStudio dashboard based on your Google Ads data.
31 |
32 | ## Prerequisites
33 |
34 | 1. Join [this group](https://groups.google.com/g/pmax-dashboard-template-readers/)
35 |
36 | 1. Obtain a Developer token
37 |
38 | a. This can be found in [Google Ads](ads.google.com) on the MCC level
39 |
40 | b. Go to Tools & Settings > Setup > API Center. If you do not see a developer token there, please complete the details and request one.
41 |
42 | c. By default, your access level is 'Test Account'; please apply for 'Basic access' if you don't have it. Follow [these instructions](https://developers.google.com/google-ads/api/docs/access-levels)
43 |
44 | 1. Create a new Google Cloud Project on the [Google Cloud Console](https://console.cloud.google.com/), **make sure it is connected to a billing account**
45 |
46 | ### Installation
47 |
48 | Click [this link](https://console.cloud.google.com/?cloudshell=true&cloudshell_git_repo=https://github.com/google/pmax_best_practices_dashboard&cloudshell_tutorial=walkthrough.md) to be redirected to a step-by-step Google Cloud tutorial on deploying pMaximizer.
49 |
50 | ### Update to the Latest Version
51 |
52 | To update the code and produce a new updated dashboard link, follow these steps. (If you wish to keep the same dashboard as you previously produced, you can, but in that case, only backend updates will be implemented.)
53 |
54 | 1. Enter the [Google Cloud Platform (GCP)](https://console.cloud.google.com/).
55 | 2. Make sure you’re in the project where you deployed the pMaximizer.
56 | 3. Activate the Cloud Shell by clicking on the "Activate Cloud Shell" icon on the upper right side of the screen: 
57 | 4. Execute (copy to the Cloud Shell and press Enter) the following commands in your Cloud Shell:
58 |
59 | ```
60 | cd pmax_best_practices_dashboard
61 | ```
62 |
63 | ```
64 | git pull
65 | ```
66 |
67 | ```
68 | sh upgrade_pmaximizer.sh
69 | ```
70 |
71 | Follow the link at the end of the deployment process to see access the upgraded dashboard, or use your previous link if you wish to only update the backend of the dashboard.
72 |
73 | ## Architecture
74 |
75 | ### What happens during installation
76 |
77 | 
78 |
79 | ### What Google Cloud components are deployed automatically
80 |
81 | 
82 |
83 | ### In depth: Gaarf → Storage
84 |
85 | 
86 |
87 | ### In depth: Gaarf → Scheduler + Workflow
88 |
89 | 
90 |
91 | ### In depth: Gaarf → Run
92 |
93 | 
94 |
95 | ### In depth: Gaarf → BigQuery
96 |
97 | 
98 |
99 | ### What happens daily post installation
100 |
101 | 
102 |
103 | ## Troubleshooting
104 |
105 | ### What technical skills do I need to deploy the dashboard?
106 |
107 | You do not need any technical skills to deploy the dashboard as it’s fully driven by clicks and “copy and paste” commands. However, you do need the Owner level permission in the Google Cloud project you’re deploying it to.
108 |
109 | ### What Google Cloud components will be added to my project?
110 |
111 | - Storage
112 | - Scheduler
113 | - Workflows
114 | - Run
115 | - BigQuery (Datasets and Data Transfer)
116 |
117 | ### The deployment was not successful, what do I do?
118 |
119 | If the deployment was unsuccessful please follow these steps to try and troubleshoot:
120 |
121 | 1. Check that all credentials in the google-ads.yaml are correct:
122 | - In The Google Cloud Platform, under the project you deployed the pMax Dashboard too, Click the “Activate Cloud Shell” icon: 
123 | - Click the “Open Editor” icon: 
124 | - In the File System, find the pmax_best_practices directory.
125 | - In the pmax_best_practices directory, find the google-ads.yaml file and click on it.
126 | - Review the credentials in the google-ads.yaml file. Make sure that they are correct, and that there are no quotation marks before any credential.
127 | - Check that the login_customer_id is all digits, with no dashes (i.e: 123456789 and not 123-456-789)
128 | - If you find a mistake, edit it in place and be sure to save, and follow the next steps. If not, please refer to “How do I see logs from my deployment?” in the next section.
129 | - Click the “Open Terminal” icon: 
130 | - In the Cloud shell, copy and paste the green code, and press the Enter key when specified:
131 | - `cd pmax_best_practices_dashboard` Press Enter
132 | - `sh upgrade_pmaximizer.sh` Press Enter
133 | - After the run finishes (may take 15-30 minutes) Check the dashboard URL to see if the deployment succeeded. (you can see instructions on how to find the dashboard URL in this document).
134 |
135 | ### How do I see the logs from my deployment?
136 |
137 | - In the Google Cloud Platform, under the project you deployed the pMax Dashboard too, click on the “Search” bar in the central upper part of the screen
138 | - Type “Logs Explorer” in the search bar and click on the following:
139 | 
140 |
141 | ### I lost the dashboard URL in the process, how can I access or find it?
142 |
143 | You can find the dashboard_url.txt file in the folder of the cloned repository or in your GCS bucket. Please see these instructions on how to access the URL through the cloud shell:
144 |
145 | - In The Google Cloud Platform, under the project you deployed too, Click the “Activate Cloud Shell” icon: 
146 | - In the Cloud shell, copy and paste the green code, and press the Enter key when specified:
147 | - Non-Retailers:
148 | - `cd pmax_best_practices_dashboard` Press Enter
149 | - `cat dashboard_url.txt` Press Enter
150 | - Retailers:
151 | - `cd pmax_best_practices_dashboard/work_retail` Press Enter
152 | - `cat dashboard_url.txt` Press Enter
153 |
154 | The dashboard URL should then appear in the Shell.
155 |
156 | ### What access level does my access token must have?
157 |
158 | Your Access Token has to have "Basic Access" or "Standard". Level "Test Account" will not work:
159 |
160 | 
161 |
162 | ### How Do I save and share the Finished Dashboard with teammates?
163 |
164 | After clicking the dashboard URL for the first time, you will see the LookerStudio dashboard. In order to save and share it you need to follow these steps:
165 |
166 | - On the upper right side of the screen, click "Save and Share"
167 | - Review the Credentials permissions of the different data sources. If you would like to give other colleagues permission to view all parts of the dashboard, even if they don’t have permissions to the Google Cloud Project it was created in, you need to change the credentials to Owner’s.
168 | - To change the credentials to Owner’s, you need to click Edit on the very most right column:
169 |
170 | 
171 |
172 | - Click on Data Credentials:
173 |
174 | 
175 |
176 | - Choose Owner’s credentials, and then Update:
177 |
178 | 
179 |
180 | - Click Done on the upper right.
181 | - Do this for all data sources in the Dashboard.
182 | - Click “Save and Share” again, and “Acknowledge and save”
183 | - Click “Add to Report”.
184 | - On the upper right, Click Share:  to share with teammates.
185 |
186 | ### How much does it cost?
187 | It heavily depends on how much data you have and how often it's used. If you check the Architecture of Components section, there are 5 cloud components: Run, Scheduler, Workflows, Storage and BigQuery. For a large amount of data (e.g. thousands of accounts, campaigns and products), we do not expect more than 10-15 USD/month in Google Cloud, mainly driven by Big Query.
188 |
189 | ### How do I edit the dashboard?
190 |
191 | Please find this Looker Studio [tutorial](https://support.google.com/looker-studio/answer/9171315?hl=en).
192 |
193 | ### What Oauth credential user type should I choose? Internal or external?
194 |
195 | If you’re a google workspace user: Internal
196 | If you’re not a google-workspace user: External. You should be ok to use it in "Test mode" instead of requesting your app to be approved by Google.
197 |
198 | ### How do I modify the results I get the dates of the data being pulled / how do I modify the hour the data is getting pulled?
199 |
200 | You can modify the answers.json file. In the GCP, open the cloud shell.
201 |
202 | ### Can I create a dashboard on paused pMax campaigns that we ran in the past?
203 |
204 | Yes! You can just change the ads_macro.start_date in answers.json file (shown above) while deploying to a value that covers the dates where the campaigns were active. By default it sets start_date to 90 days ago.
205 |
206 | ### Can I deploy it in an existing Cloud Project or do I need to create a new one just for this dashboard?
207 |
208 | You can use an existing Project if you want to. However, please remember that the best practice for clients is to create a new project dedicated to this solution (or any new solution).
209 |
210 | ### Which GAQL queries are executed?
211 |
212 | Please refer to the folder google_ads_queries.
213 |
214 | ### Can I create a dashboard on paused pMax campaigns that we ran in the past?
215 |
216 | Yes! You can just change the ads_macro.start_date in answers.json file while deploying
217 | to a value that covers the dates where the campaigns were active. By default it sets start_date to 90 days ago.
218 |
219 | ### Can I deploy it in an existing Cloud Project or do I need to create a new one just for this dashboard?
220 |
221 | You can use an existing Project if you want to. However, please remember that the best practice for clients is to create a new project dedicated to this solution (or any new solution).
222 |
223 | ### How can I modify the dashboard from a non-retail version to a retail version?
224 |
225 | 1. Enter the [Google Cloud Platform (GCP)](https://console.cloud.google.com/).
226 | 2. Make sure you’re in the project you deployed the pMaximizer to.
227 | 3. Activate the Cloud Shell by clicking on the "Activate Cloud Shell" icon on the upper right side of the screen: 
228 | 4. Execute (copy to the cloud shell and press enter) the following commands in your Cloud Shell:
229 |
230 | ```
231 | cd pmax_best_practices_dashboard
232 | ```
233 |
234 | ```
235 | git pull
236 | ```
237 |
238 | ```
239 | sh non_retail_to_retail_upgrade.sh
240 | ```
241 |
242 | Follow the link at the end of the deployment process to access your new retail pMaximizer.
243 |
244 | **If you can’t find an answer for your question/a solution to your problem here, please reach out to pmax_bpdash@google.com.**
245 |
246 | ## Disclaimer
247 |
248 | ** This is not an officially supported Google product.**
249 |
250 | Copyright 2021 Google LLC. This solution, including any related sample code or data, is made available on an “as is,” “as available,” and “with all faults” basis, solely for illustrative purposes, and without warranty or representation of any kind. This solution is experimental, unsupported and provided solely for your convenience. Your use of it is subject to your agreements with Google, as applicable, and may constitute a beta feature as defined under those agreements. To the extent that you make any data available to Google in connection with your use of the solution, you represent and warrant that you have all necessary and appropriate rights, consents and permissions to permit Google to use and process that data. By using any portion of this solution, you acknowledge, assume and accept all risks, known and unknown, associated with its usage, including with respect to your deployment of any portion of this solution in your systems, or usage in connection with your business, if at all.
251 |
--------------------------------------------------------------------------------