본문으로 건너뛰기
블로그로 돌아가기
측정·분석

GA4 내부 트래픽이 BigQuery에 남는 이유와 쿼리로 거르는 법

GA4 내부 트래픽 필터를 켰는데 BigQuery에 사내 접속이 남는다면 필터가 테스트나 사용 안 함 상태일 가능성이 크다. 상태 확인법과 traffic_type으로 세션째 거르는 쿼리, 뷰로 고정하는 법을 정리했다.

7분 소요측정·분석
GA4BigQuery내부 트래픽데이터 필터traffic_type
GA4 내부 트래픽이 BigQuery에 남는 이유와 쿼리로 거르는 법

GA4에서 내부 트래픽 필터를 켰는데 BigQuery에 사내 접속이 남아 있다면, 필터가 아직 '사용' 상태가 아닐 가능성이 크다. 구글 공식 문서에 따르면 '사용(Active)' 상태의 제외 필터는 데이터를 영구히 빼고, 그 데이터는 GA4에도 BigQuery에도 남지 않는다. 반대로 '테스트' 상태는 표시만 하고 데이터를 그대로 둔다. 이미 쌓인 데이터는 BigQuery 쿼리에서 세션 단위로 거르면 된다.

세 줄로 먼저 읽기

  • 필터 상태가 '테스트'나 '사용 안 함'이면 사내 접속은 BigQuery에 그대로 들어간다.
  • 내부 접속에는 traffic_type 값이 붙어서 BigQuery에서도 골라낼 수 있다.
  • BigQuery 연결 설정으로는 거를 수 없다. 쿼리나 뷰에서 세션째 빼야 한다.

필터 상태 세 가지가 결과를 가른다

GA4 데이터 필터에는 상태가 세 가지 있다. 이름은 비슷해도 데이터에 하는 일이 완전히 다르다. 근거는 구글의 내부 트래픽 필터 안내다.

상태하는 일BigQuery에 남나
테스트맞는 데이터에 '테스트 데이터 필터 이름' 표시만 붙인다남는다
사용들어오는 데이터에서 영구히 뺀다남지 않는다
사용 안 함필터를 평가하지 않는다남는다

많이들 헷갈리는 지점이 여기다. 필터를 만들면 처음에는 테스트 상태로 두는 경우가 많다. 탐색 보고서에서 걸러지는지 확인하려는 것이다. 그런데 이 상태로는 아무것도 빠지지 않는다. 확인을 끝낸 뒤 '사용'으로 바꿔야 비로소 제외된다.

주의할 점도 있다. 사용 상태의 효과는 영구적이다. 한번 빠진 데이터는 되살릴 수 없다. 그래서 테스트로 먼저 확인하는 순서 자체는 맞다. 바꾸는 걸 잊지만 않으면 된다.

필터 상태 세 가지와 결과. 테스트는 켜져 있어도 사내 접속이 BigQuery에 남고, 사용은 영구히 빠지며, 사용 안 함은 BigQuery에 남는다.
테스트 상태는 표시만 한다. 사용으로 바꿔야 실제로 빠진다.

BigQuery만 보고는 테스트인지 꺼졌는지 모른다

테스트 상태에서 붙는 '테스트 데이터 필터 이름'은 GA4 탐색 보고서에서 보는 값이다. BigQuery 내보내기 스키마에는 이 값이 따로 없다. 그러니 BigQuery에 사내 접속이 남아 있다는 사실만으로는 테스트인지 사용 안 함인지 가릴 수 없다.

상태는 GA4 관리 화면에서 확인한다. 관리 → 데이터 수집 및 수정 → 데이터 필터에서 해당 필터의 상태 열을 보면 된다. 여기서 '사용'이 아니면 지금도 내부 접속이 BigQuery로 들어가고 있다.

내부 접속은 traffic_type으로 골라낸다

내부 트래픽 규칙을 만들면 GA4는 해당 IP에서 들어온 모든 이벤트에 traffic_type 파라미터를 붙인다. 기본값은 internal이다. 이벤트 파라미터는 BigQuery의 event_params에 함께 내보내지므로, 쿼리에서 이 값으로 사내 접속을 찾을 수 있다.

실제 운영 데이터에서 관측한 사례다(합성 예시가 아니며, 서비스 이름과 수치는 익명화했다). 한 서비스의 내보내기 데이터를 보니, 내부 트래픽 규칙을 만든 뒤에도 traffic_type='internal'이 붙은 세션이 계속 남아 있었다. 전체 방문 중 일부가 사내 접속이었고, 그만큼 방문 수가 부풀어 있었다. 다행히 이 세션들에서 나온 문의(리드)는 없었다.

BigQuery 연결 설정으로 거르면 되지 않을까 싶지만 안 된다. BigQuery 연결의 데이터 필터링은 데이터 스트림과 이벤트 이름 단위로만 뺄 수 있다. 파라미터 값으로는 거를 수 없다.

쿼리에서 세션째 거르는 법

핵심은 이벤트가 아니라 세션 단위로 빼는 것이다. 한 세션 안에서도 첫 이벤트에만 표시가 빠지거나, 규칙을 만든 시점 전후로 섞일 수 있다. 이벤트만 지우면 세션의 반쪽이 남아 방문 수와 전환율이 둘 다 틀어진다.

WITH events AS (
  SELECT
    user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'traffic_type') AS traffic_type,
    COALESCE(
      (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'debug_mode'),
      SAFE_CAST((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'debug_mode') AS INT64)
    ) AS debug_mode
  FROM `프로젝트.analytics_속성ID.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20260901' AND '20260914'
),
session_flags AS (
  SELECT
    user_pseudo_id, session_id,
    LOGICAL_OR(IFNULL(traffic_type = 'internal', FALSE)) AS is_internal,
    LOGICAL_OR(IFNULL(debug_mode = 1, FALSE)) AS is_debug
  FROM events
  GROUP BY user_pseudo_id, session_id
)
SELECT
  COUNT(*) AS all_sessions,
  COUNTIF(NOT is_internal AND NOT is_debug) AS external_sessions
FROM session_flags;

IFNULL(..., FALSE)를 꼭 넣자. 표시가 없는 세션은 비교 결과가 비어(NULL) 버려서, 그대로 두면 일반 방문까지 집계에서 빠진다.

세 가지를 같이 본다. traffic_type은 사내 IP 접속이다. debug_mode는 GTM 미리보기나 디버그 확장으로 들어온 개발자 접속이다. 필요하면 page_location의 호스트가 운영 도메인이 아닌 것(로컬, 개발 서버)도 뺀다. 개발 환경과 운영 환경을 호스트명으로 나누는 방법은 Meta Pixel 개발·운영 전환 분리 글에 GTM 설정으로 정리해 두었다. NET.HOST(page_location)로 호스트만 뽑을 수 있다.

뷰로 고정해 두자

매번 이 조건을 기억하는 건 어렵다. 같은 이유로 UTM 값도 표로만 관리하면 어긋나서, UTM 컨벤션을 BigQuery로 주기적으로 검증하는 글에서도 규칙을 쿼리로 고정하는 방법을 다뤘다. 조건을 뷰로 만들어 두고 대시보드와 분석은 뷰만 읽게 하면 실수가 줄어든다.

CREATE OR REPLACE VIEW `프로젝트.분석.external_events` AS
WITH base AS (
  SELECT *,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
    IFNULL((SELECT value.string_value FROM UNNEST(event_params)
            WHERE key = 'traffic_type') = 'internal', FALSE) AS is_internal_event
  FROM `프로젝트.analytics_속성ID.events_*`
),
flagged AS (
  SELECT *,
    LOGICAL_OR(is_internal_event) OVER (PARTITION BY user_pseudo_id, session_id) AS session_is_internal
  FROM base
)
SELECT * EXCEPT (session_id, is_internal_event, session_is_internal)
FROM flagged
WHERE NOT session_is_internal;

뷰는 읽을 때마다 원본을 다시 계산한다. 데이터가 크면 날짜 조건을 꼭 걸고 읽자. 자주 쓰면 세션 표를 따로 만들어 두는 편이 비용이 적다.

놓치기 쉬운 점

  1. 필터는 과거에 소급되지 않는다. 공식 문서대로 필터는 만든 시점부터 적용된다. 사용으로 바꿔도 그 전에 쌓인 사내 접속은 BigQuery에 남는다. 과거분은 쿼리로 걸러야 한다.
  2. IP가 바뀌는 접속은 못 잡는다. 재택 근무, 휴대폰 데이터, VPN처럼 사내 IP가 아닌 곳에서 들어오면 내부 표시가 붙지 않는다. 이건 필터의 한계라서, 팀원 기기에 따로 표시를 남기는 방식을 더해야 한다.
  3. 이벤트 단위 제외는 반쪽짜리다. 앞에서 본 대로 세션째 빼야 방문 수와 전환율이 같이 맞는다.

자주 묻는 질문

필터를 '사용'으로 바꾸면 BigQuery에서도 빠지나?
빠진다. 구글 공식 문서에 따르면 사용 상태의 제외 필터로 걸린 데이터는 처리되지 않고 GA4와 BigQuery 어디에도 남지 않는다. 다만 바꾼 시점 이후 데이터에만 적용된다.

BigQuery에서 테스트 상태를 확인할 수 있나?
내보내기 스키마에는 테스트 필터 이름이 없다. 상태는 GA4 관리 화면의 데이터 필터 목록에서 확인한다.

traffic_type 값을 바꿔도 되나?
된다. 기본값은 internal이지만 지사별로 다른 값을 줄 수 있다. 그러면 쿼리의 조건도 그 값에 맞춰야 한다.

새로 바뀐 기능을 알리는 소식이 아니라, 기존 기능의 동작을 정리한 가이드다. 공식 문서 확인: 2026년 9월 29일. 사례 수치는 익명화했다. 이미지는 개념을 설명하는 생성 일러스트다.

같은 주제 글

이 글이 도움이 되었다면 공유해주세요

최신 인사이트

관련 프로젝트

새 글을 이메일로 받아보세요

마케팅, 분석, 개발 인사이트를 정리해서 보내드려요.