- Support Home
- BigQuery
Sample BigQuery Queries
WITH -- grabbing the latest version of each serp in case of reparse latest_filtered_rankings AS ( SELECT AS VALUE ARRAY_AGG(t ORDER BY inserted_at DESC LIMIT 1)[OFFSET(0)] -- you'll insert the workspace/project slugs, so this will look like -- FROM nozzledata.myworkspace_myproject.rankings t FROM nozzledata._.rankings t -- ranking data is partitioned daily on the "requested" field, which is the timestamp based on the schedule. -- There is a BigQuery requirement to filter on this field, which will also help reduce query costs -- for most daily/weekly requests, the time component will be 00:00:00, but hourly schedules will be on the hour every hour. -- Here are a few common query patterns: WHERE DATE(requested) BETWEEN '2024-02-28' AND '2024-03-01' -- WHERE DATE(requested) >= '2024-01-01' -- to get 100% of all historical results, set this before you started tracking with Nozzle -- WHERE requested >= TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -30 DAY) -- last 30 days GROUP BY keyword_id, requested ), latest_filtered_rankings_results AS ( SELECT requested, keyword_id, phrase, device, language, country, location_type, location, -- this filters out built-in keyword groups like "- All Keywords -" (SELECT ARRAY_AGG(kg) FROM UNNEST(keyword_groups) kg WHERE NOT STARTS_WITH(kg, '- ')) AS keyword_groups, keyword_metrics.adwords_search_volume AS search_volume, -- result data result.title.text as title, result.description.text as description, result.url.domain as domain, result.url.url as url, result.paid_adjusted_rank AS paid_adjusted_rank, result.rank AS rank, result.item_rank AS item_rank, -- calculate base rank (only featured snippets or 10 blue links) IF(result.organic.is_organic IS TRUE OR result.featured_snippet.is_featured_snippet IS TRUE, DENSE_RANK() OVER (PARTITION BY keyword_id, requested, result.organic.is_organic IS TRUE OR (result.featured_snippet.is_featured_snippet IS TRUE AND result.parent_item_rank IS NULL) ORDER BY result.rank), NULL ) AS base_rank, -- visibility (recursively checked in Chrome for CSS properties like display:none, opacity, visibility, etc) result.measurements.is_visible AS is_visible, -- calculated metrics result.nozzle_metrics.click_through_rate AS click_through_rate, result.nozzle_metrics.estimated_traffic AS estimated_traffic, result.measurements.pixels_from_top AS pixels_from_top, result.measurements.percentage_of_viewport AS above_the_fold_percentage, -- 100% = 1 | 5% = 0.05 result.measurements.percentage_of_dom AS serp_percentage, -- 100% = 1 | 5% = 0.05 -- some advanced aggregation examples. For aggregated metrics, we'd use a different query, -- these are primarily for isolating SERPs that match, then returning result level data -- how many product packs are on the SERP, and a breakout if they are in the top 3 COUNTIF(result.product.is_product IS TRUE AND result.layout.is_pack IS TRUE) OVER (PARTITION BY keyword_id, requested) AS product_pack_count, COUNTIF(result.product.is_product IS TRUE AND result.layout.is_pack IS TRUE AND rank BETWEEN 1 AND 3) OVER (PARTITION BY keyword_id, requested) AS product_pack_top_3_count, -- how many visible products are on the SERP and how many total products (typically non-visible products are in a carousel) COUNTIF(result.product.is_product IS TRUE AND result.measurements.is_visible IS TRUE) OVER (PARTITION BY keyword_id, requested) AS visible_product_count, COUNTIF(result.product.is_product IS TRUE) OVER (PARTITION BY keyword_id, requested) AS product_count, -- this is a subset of SERP features. You will likely not care about many of these, -- and for some that match your business, you may want to get more granular (SELECT ARRAY_AGG(sf) FROM UNNEST([ -- for export to CSV, change "ARRAY_AGG(sf)" to "STRING_AGG(sf, '; ')" IF(result.direct_answer.is_direct_answer IS TRUE, 'direct_answer', NULL), IF(result.converter.is_unit_converter IS TRUE OR result.converter.is_currency_converter IS TRUE OR result.converter.is_exchange_rate IS TRUE, 'converter', NULL), IF(result.dictionary.is_dictionary IS TRUE, 'dictionary', NULL), IF(result.weather.is_weather IS TRUE, 'weather', NULL), IF(result.sport.is_sport IS TRUE, 'sport', NULL), IF(result.translate.is_translate IS TRUE, 'translate', NULL), IF(result.chart.is_chart IS TRUE OR result.chart.has_chart IS TRUE, 'chart', NULL), IF(result.table.is_table IS TRUE OR result.table.has_table IS TRUE, 'table', NULL), IF(result.list.is_bulleted IS TRUE OR result.list.is_numbered IS TRUE, 'list', NULL), IF(result.directory.is_directory IS TRUE, 'directory', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE, 'featured_snippet', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE AND (result.table.is_table IS TRUE OR result.table.has_table IS TRUE), 'featured_snippet_table', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE AND result.list.is_bulleted IS TRUE, 'featured_snippet_bulleted_list', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE AND result.list.is_numbered IS TRUE, 'featured_snippet_numbered_list', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE AND (result.image.is_image IS TRUE OR result.image.has_image IS TRUE), 'featured_snippet_image', NULL), IF(result.featured_snippet.is_featured_snippet IS TRUE AND (result.video.is_video IS TRUE OR result.video.has_video IS TRUE), 'featured_snippet_video', NULL), IF(result.according_to.is_according_to IS TRUE, 'according_to', NULL), IF(result.layout.is_pack AND result.image.is_image IS TRUE, 'image_pack', NULL), IF(result.layout.is_pack AND result.video.is_video IS TRUE, 'video_pack', NULL), IF(result.product.is_product IS TRUE AND NOT result.paid.is_paid IS TRUE, 'product', NULL), IF(result.product.is_product IS TRUE AND result.paid.is_paid IS TRUE, 'product_paid', NULL), IF(result.price.has_price IS TRUE OR result.price.has_price_range IS TRUE, 'price', NULL), IF(result.discount.has_discount IS TRUE OR result.discount.has_deal IS TRUE, 'discount', NULL), IF(result.best.is_best IS TRUE, 'best', NULL), IF(result.comparison.is_comparison IS TRUE, 'comparison', NULL), IF(result.top_rated.is_top_rated IS TRUE, 'top_rated', NULL), IF(result.destination.is_destination IS TRUE, 'destination', NULL), IF(result.hotel.is_hotel IS TRUE, 'hotel', NULL), IF(result.flight.is_flight IS TRUE, 'flight', NULL), IF(result.map_travel.is_map_travel IS TRUE, 'map_travel', NULL), IF(result.map.is_map IS TRUE, 'map', NULL), IF(result.busyness.is_busyness IS TRUE, 'busyness', NULL), IF(result.claim.is_claim IS TRUE, 'claim', NULL), IF(result.sitelink.is_sitelink IS TRUE, 'sitelink', NULL), IF(result.sitelink.is_expanded_sitelink IS TRUE, 'expanded_sitelink', NULL), IF(result.sitelink.is_sitelink IS TRUE AND result.paid.is_paid IS TRUE, 'sitelink_paid', NULL), IF(result.sitelink.is_expanded_sitelink IS TRUE AND result.paid.is_paid IS TRUE, 'expanded_sitelink_paid', NULL), IF(result.entertainment.is_movie_rating IS TRUE OR result.entertainment.is_on_tv_soon IS TRUE OR result.entertainment.is_cast IS TRUE OR result.entertainment.is_watch_movie IS TRUE OR result.entertainment.is_watch_show IS TRUE OR result.entertainment.is_episode IS TRUE OR result.entertainment.is_trailer_clip IS TRUE OR result.entertainment.is_based_on_the_book IS TRUE OR result.entertainment.is_top_voted_tag IS TRUE, 'entertainment', NULL), IF(result.podcast.is_podcast IS TRUE, 'podcast', NULL), IF(result.book.is_book IS TRUE OR result.book.is_ebook IS TRUE OR result.book.is_audiobook IS TRUE OR result.book.is_author IS TRUE OR result.book.is_book_preview IS TRUE OR result.book.is_borrow_ebook IS TRUE OR result.book.is_get_book IS TRUE, 'book', NULL), IF(result.available_on.is_available_on IS TRUE, 'available_on', NULL), IF(result.showtimes.is_showtimes IS TRUE, 'showtimes', NULL), IF(result.music.is_music IS TRUE OR result.music.is_lyrics IS TRUE OR result.music.is_other_recording IS TRUE OR result.music.is_listen IS TRUE OR result.music.is_song IS TRUE OR result.music.is_album IS TRUE, 'music', NULL), IF(result.app.is_app IS TRUE, 'app', NULL), IF(result.people_also_ask.is_people_also_ask IS TRUE, 'people_also_ask', NULL), IF(result.faq.is_faq IS TRUE, 'faq', NULL), IF(result.consideration.is_consideration IS TRUE, 'consideration', NULL), IF(result.things_to_know.is_things_to_know IS TRUE, 'things_to_know', NULL), IF(result.people_also_search_for.is_people_also_search_for IS TRUE, 'people_also_search_for', NULL), IF(result.refine_by.is_refine_by IS TRUE, 'refine_by', NULL), IF(result.related_search.is_related_search IS TRUE, 'related_search', NULL), IF(result.related_phrase.is_related_phrase_misc IS TRUE, 'related_phrase_misc', NULL), IF(result.forum.is_forum IS TRUE, 'forum', NULL), IF(result.question_and_answer.is_question_and_answer IS TRUE, 'question_and_answer', NULL), IF(result.news.is_news IS TRUE, 'news', NULL), IF(result.top_story.is_top_story IS TRUE, 'top_story', NULL), IF(result.latest_from.is_latest_from IS TRUE, 'latest_from', NULL), IF(result.news.is_news_misc IS TRUE, 'news_misc', NULL), IF(result.interesting_find.is_interesting_find IS TRUE, 'interesting_find', NULL), IF(result.discover_more.is_discover_more IS TRUE, 'discover_more', NULL), IF(result.found_on_the_web.is_found_on_the_web IS TRUE, 'found_on_the_web', NULL), IF(result.find_results_on.is_find_results_on IS TRUE, 'find_results_on', NULL), IF(result.event.is_event IS TRUE, 'event', NULL), IF(result.job.is_job IS TRUE, 'job', NULL), IF(result.college.is_college IS TRUE, 'college', NULL), IF(result.auto.is_auto IS TRUE, 'auto', NULL), IF(result.medical.is_medical IS TRUE, 'medical', NULL), IF(result.medical.is_related_condition IS TRUE, 'medical_related_condition', NULL), IF(result.medical.is_related_medication IS TRUE, 'medical_related_medication', NULL), IF(result.medical.is_may_treat IS TRUE, 'medical_may_treat', NULL), IF(result.medical.is_symptom IS TRUE, 'medical_symptom', NULL), IF(result.medical.is_treatment IS TRUE, 'medical_treatment', NULL), IF(result.about.is_about IS TRUE, 'about', NULL), IF(result.attribute.is_attribute IS TRUE, 'attribute', NULL), IF(result.knowledge_graph.is_knowledge_graph IS TRUE, 'knowledge_graph', NULL), IF(result.research.is_research IS TRUE, 'research', NULL), IF(result.cited_source.is_cited_source IS TRUE, 'cited_source', NULL), IF(result.bio.is_bio IS TRUE, 'bio', NULL), IF(result.profile.is_profile IS TRUE, 'profile', NULL), IF(result.quote.is_quote IS TRUE, 'quote', NULL), IF(result.recipe.is_recipe IS TRUE, 'recipe', NULL), IF(result.twitter.is_twitter IS TRUE, 'twitter', NULL), IF(result.finance.is_finance IS TRUE OR result.finance.is_stock_market IS TRUE OR result.finance.is_market_ticker IS TRUE OR result.finance.is_ticker_price_stats IS TRUE, 'finance', NULL), IF(result.story.is_story IS TRUE, 'story', NULL), IF(result.how_to.is_how_to IS TRUE, 'how_to', NULL), IF(result.organic.is_organic IS TRUE, 'organic', NULL) ]) sf WHERE sf IS NOT NULL) AS serp_features, FROM latest_filtered_rankings JOIN UNNEST(results) AS result -- this table has one row per unique keyword_id (phrase + locale + device), and all keyword groups -- aggregated, even if the same keyword belongs to multiple keyword sources, and shows the most -- current keyword configuration and keyword groups. JOIN nozzledata._.latest_keywords_by_keyword_id USING (keyword_id) -- here are common filters people use -- we use QUALIFY here instead of WHERE because of the window aggregation functions. -- if you use WHERE, it will filter before aggregating, which may impact the output QUALIFY product_pack_top_3_count > 0 AND result.url.domain = 'chewy.com' AND result.featured_snippet.is_featured_snippet IS TRUE AND product_count > 30 ) SELECT * FROM latest_filtered_rankings_results ORDER BY phrase, device, requested, paid_adjusted_rank, item_rank