해당 글에서는 Google Search Console에서 수집된 데이터를 google-api-services-searchconsole 라이브러리를 활용하여서 데이터를 불러오는 API 활용 방법에 대해서 알아봅니다
![]()
💡 [참고] 이전에 Google Analaytics를 연동한 내용에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
[Java] GA4(Google Analytics) 이해하고 활용하기 -2: 수집된 데이터 조회 환경 설정 및 활용 방법
해당 글에서는 GA에서 수집된 데이터를 API를 통해서 가져와서 화면상에 출력하는 과정을 포함한 글입니다.💡 [참고] React 환경에서 수집한 데이터에 대해서 Spring Boot 환경에서 이를 조회하는 방
adjh54.tistory.com
1) GSC(Google Search Console)
💡 GSC(Google Search Console)
- Google이 무료로 제공하는 웹마스터 도구로, 내 웹사이트가 Google 검색에서 어떻게 노출되고 있는지 모니터링하고 최적화할 수 있는 서비스를 의미합니다.
1. GSC 주요 기능 요약

| 기능 | 설명 | 주요 사항 |
| 실적 (Performance) | 검색 결과에서의 사이트 성과 분석 | 클릭수, 노출수, CTR, 평균 게재순위 |
| URL 검사 (URL Inspection) | 특정 URL의 크롤링/색인 상태 확인 | 색인 여부, 모바일 사용성, 구조화 데이터 유효성 |
| 페이지 색인 생성 | 전체 사이트의 색인 현황 보고서 | 색인된 페이지 수, 미색인 사유 |
| 사이트맵 (Sitemaps) | sitemap.xml 제출 및 상태 추적 | 제출 URL 수 vs 색인 URL 수 |
| 코어 웹 바이탈 | 페이지 로딩/반응 성능 측정 | LCP, INP, CLS |
| 모바일 사용성 | 모바일 환경 문제 감지 | 텍스트 크기, 터치 요소 간격, 뷰포트 설정 |
| 구조화된 데이터 | 리치 결과(Rich Results) 유효성 검사 | FAQ, 제품, 리뷰 등 스키마 오류/경고 |
| 링크 (Links) | 내부/외부 링크 구조 분석 | 백링크 현황, 앵커 텍스트, 상위 연결 사이트 |
2. 실적 보고서 주요 지표

| 기능 | 지표 설명 | 포인트 |
| 총 클릭수 | 검색 결과에서 사이트를 클릭한 횟수 | 실제 유입 트래픽 파악 |
| 총 노출수 | 검색 결과에 사이트가 표시된 횟수 | 검색 가시성 측정 |
| 평균 CTR | 노출 대비 클릭 비율 (%) | 메타 타이틀/디스크립션 효과 판단 |
| 평균 게재순위 | 검색 결과 내 평균 위치 | SEO 개선 효과 추적 |
2) 환경 구성하기 -1 : Google Cloud 서비스 허용
1. Google Cloud에 접속

Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
2. API 및 서비스를 선택합니다

3. 라이브러리 > Google Search Console API를 선택합니다
💡 라이브러리 > Google Search Console API를 선택합니다

4. ‘사용’ 버튼을 누릅니다

5. API 및 서비스 > 사용자 인증 정보 탭으로 이동하여 서비스 계정을 확인합니다
💡 API 및 서비스 > 사용자 인증 정보 탭으로 이동하여 서비스 계정을 확인합니다
- 서비스 계정 이메일을 복사해 둡니다.
- GA로 이미 사용을 하는 경우, 동일한 서비스 계정을 이용해도 됩니다.

💡 [참고] 추가 신규 사용자의 경우는 아래의 GA 설정 글을 따라서 구성하시면 됩니다.
[Java] GA4(Google Analytics) 이해하고 활용하기 -2: 수집된 데이터 조회 환경 설정 및 활용 방법
해당 글에서는 GA에서 수집된 데이터를 API를 통해서 가져와서 화면상에 출력하는 과정을 포함한 글입니다.💡 [참고] React 환경에서 수집한 데이터에 대해서 Spring Boot 환경에서 이를 조회하는 방
adjh54.tistory.com
2) 환경 구성하기 -2 : Google Search Console 사용자 추가
1. Google Search Console에 접속합니다

Google Search Console
Search Console 도구와 보고서를 사용하면 사이트의 검색 트래픽 및 실적을 측정하고, 문제를 해결하며, Google 검색결과에서 사이트가 돋보이게 할 수 있습니다.
search.google.com
2. 설정 > 사용자 추가 버튼을 누릅니다

3. 이전 단계에서 복사해 둔 이메일을 추가하면 설정은 완료가 됩니다.

4) Google Search Console API
💡 Google Search Console API
- Google Search Console로부터 수집된 정보를 API로 전달을 받아서 프로그래밍 방식으로 접근할 수 있는 HTTP REST 서비스를 의미합니다.
- 속성(사이트) 관리, 사이트맵 제출, 검색 실적 데이터 조회, URL 검사를 API로 처리할 수 있습니다.
개요 | Search Console API | Google for Developers
속성 및 사이트맵을 확인, 추가 또는 삭제하고, Google 검색결과 데이터에서 쿼리를 실행하고, 페이지를 테스트하는 데 사용하는 API의 개요를 확인하세요.
developers.google.com
1. 라이브러리 설치
implementation 'com.google.apis:google-api-services-searchconsole:v1-rev20250122-2.0.0' // Google Search Console API

Maven Repository: com.google.apis » google-api-services-searchconsole
mvnrepository.com
2. SearchConsoleConfig
💡 SearchConsoleConfig
- Spring Boot 애플리케이션에서 Google Search Console API를 사용할 수 있도록 연동 클라이언트(SearchConsole)를 생성하고 관리하는 설정(Configuration) 클래스입니다.
- 내부적으로 ga-key.json 파일을 불러와서 구글 인증 및 권한 설정을 수행합니다.
- SearchConsole.Builder를 통해서 최종 클라이언트의 빌드를 수행합니다.
package com.xxx.xxx.config;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.searchconsole.v1.SearchConsole;
import com.google.api.services.searchconsole.v1.SearchConsoleScopes;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
@Configuration
public class SearchConsoleConfig {
@Bean
public SearchConsole searchConsoleClient() throws Exception {
GoogleCredentials credentials = GoogleCredentials
.fromStream(new ClassPathResource("ga-key.json").getInputStream())
.createScoped(SearchConsoleScopes.WEBMASTERS_READONLY);
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);
return new SearchConsole.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
GsonFactory.getDefaultInstance(),
requestInitializer
).setApplicationName("xxx-xxx").build();
}
}
3. SearchConsoleService
💡 SearchConsoleService
- 사전에 구성된 SearchConsoleConfig에서 생성된 클라이언트를 기반으로 이를 활용하여서 google search console로부터 조회를 해옵니다.
| 필드 | dimensions 인덱스 | 값 예시 | 설명 |
| date | keys.get(0) | 2026-05-20 | 검색 발생 날짜 |
| query | keys.get(1) | 검색 | 사용자가 검색한 키워드 |
| page | keys.get(2) | https://xxx.com/about | 노출된 페이지 URL |
| country | keys.get(3) | kor | 국가 코드 |
| device | keys.get(4) | DESKTOP | 디바이스 종류 |
| siteUrl | (파라미터로 전달) | https://xxx.com | 조회 대상 사이트 URL |
| clicks | getClicks() | 42 | 검색 결과 클릭 수 |
| impressions | getImpressions() | 1500 | 검색 결과 노출 수 |
| ctr | getCtr() | 0.028 | 클릭률 (clicks ÷ impressions) |
| position | getPosition() | 8.3 | 평균 검색 노출 순위 (낮을수록 상위) |
import com.daekyocns.homepage.model.dto.SearchConsoleResponseDto;
import com.google.api.services.searchconsole.v1.SearchConsole;
import com.google.api.services.searchconsole.v1.model.ApiDataRow;
import com.google.api.services.searchconsole.v1.model.SearchAnalyticsQueryRequest;
import com.google.api.services.searchconsole.v1.model.SearchAnalyticsQueryResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
@Service
public class SearchConsoleService {
// Google Search Console API 클라이언트 (Bean으로 주입)
private final SearchConsole client;
// application.yml의 search-console.site-urls 값 (여러 사이트 URL 배열)
@Value("${search-console.site-urls}")
private String[] siteUrls;
public SearchConsoleService(SearchConsole client) {
this.client = client;
}
/**
* 등록된 모든 사이트의 Search Analytics 데이터를 조회한다.
*
* @param startDate 조회 시작일 (yyyy-MM-dd)
* @param endDate 조회 종료일 (yyyy-MM-dd)
* @return 전체 사이트의 검색 분석 데이터 목록
*/
public List<SearchConsoleResponseDto> getSearchAnalytics(String startDate, String endDate) throws Exception {
return Arrays.stream(siteUrls)
.flatMap(siteUrl -> {
try {
// 사이트별로 데이터를 조회하여 하나의 스트림으로 병합
return fetchBySite(siteUrl, startDate, endDate).stream();
} catch (Exception e) {
// 특정 사이트 조회 실패 시 해당 사이트는 건너뛰고 계속 진행
return Stream.of();
}
})
.toList();
}
/**
* 특정 사이트의 Search Analytics 데이터를 Google API로 조회한다.
*
* @param siteUrl 조회할 사이트 URL
* @param startDate 조회 시작일
* @param endDate 조회 종료일
* @return 해당 사이트의 검색 분석 데이터 목록
*/
private List<SearchConsoleResponseDto> fetchBySite(String siteUrl, String startDate, String endDate) throws Exception {
// 쿼리 요청 구성: 날짜 범위, 집계 기준(date/query/page/country/device), 최대 행 수
SearchAnalyticsQueryRequest request = new SearchAnalyticsQueryRequest()
.setStartDate(startDate)
.setEndDate(endDate)
.setDimensions(List.of("date", "query", "page", "country", "device"))
.setRowLimit(1000); // 최대 1000행 반환
// Google Search Console API 호출
SearchAnalyticsQueryResponse response = client.searchanalytics()
.query(siteUrl, request)
.execute();
// 데이터가 없는 경우 빈 리스트 반환
if (response.getRows() == null) return List.of();
// 응답 행(row)을 DTO로 변환하여 반환
return response.getRows().stream()
.map(row -> toDto(row, siteUrl))
.toList();
}
/**
* API 응답 행(ApiDataRow)을 SearchConsoleResponseDto로 변환한다.
* dimensions 순서: [0] date, [1] query, [2] page, [3] country, [4] device
*
* @param row Google API 응답의 단일 행
* @param siteUrl 해당 행이 속한 사이트 URL
* @return 변환된 DTO
*/
private SearchConsoleResponseDto toDto(ApiDataRow row, String siteUrl) {
return SearchConsoleResponseDto.builder()
.siteUrl(siteUrl)
.date(row.getKeys().get(0)) // 날짜
.query(row.getKeys().get(1)) // 검색 키워드
.page(row.getKeys().get(2)) // 노출 페이지 URL
.country(row.getKeys().get(3)) // 국가 코드 (예: KOR)
.device(row.getKeys().get(4)) // 디바이스 (DESKTOP / MOBILE / TABLET)
.clicks(row.getClicks().longValue()) // 클릭 수
.impressions(row.getImpressions().longValue()) // 노출 수
.ctr(row.getCtr()) // 클릭률
.position(row.getPosition()) // 평균 검색 순위
.build();
}
}
4. SearchConsoleResponseDto
package com.xxx.xxx.model.dto;
import lombok.Builder;
import lombok.Getter;
/**
* Google Search Console API 검색 분석 응답 DTO
* dimensions: date / query / page / country / device
* metrics: clicks / impressions / ctr / position
*
* @author : leejonghoon
* @fileName : SearchConsoleResponseDto
* @since : 26. 5. 18.
*/
@Getter
@Builder
public class SearchConsoleResponseDto {
private String siteUrl;
private String date; // 날짜 (yyyy-MM-dd)
private String query; // 검색 키워드
private String page; // 노출 페이지 URL
private String country; // 국가 코드 (예: KOR, USA)
private String device; // 디바이스 (DESKTOP / MOBILE / TABLET)
private long clicks; // 클릭 수
private long impressions; // 노출 수
private double ctr; // 클릭률 (0.0 ~ 1.0)
private double position; // 평균 검색 순위
}
5. SearchConsoleController
package com.xxx.xxx.controller;
import com.daekyocns.homepage.model.common.ApiResponseWrapper;
import com.daekyocns.homepage.model.common.SuccessCode;
import com.daekyocns.homepage.model.dto.GaRequestDto;
import com.daekyocns.homepage.model.dto.SearchConsoleResponseDto;
import com.daekyocns.homepage.service.SearchConsoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@RestController
@RequestMapping(value = "/api/searchconsole")
public class SearchConsoleController {
private final SearchConsoleService searchConsoleService;
public SearchConsoleController(SearchConsoleService searchConsoleService) {
this.searchConsoleService = searchConsoleService;
}
@PostMapping("/analytics")
public ResponseEntity<ApiResponseWrapper<List<SearchConsoleResponseDto>>> getAnalytics(@RequestBody GaRequestDto request) {
log.debug("[+] getSearchConsoleAnalytics CALL");
try {
List<SearchConsoleResponseDto> list = searchConsoleService.getSearchAnalytics(
request.getStartDate(),
request.getEndDate()
);
log.debug("list: " + list);
ApiResponseWrapper<List<SearchConsoleResponseDto>> arw = ApiResponseWrapper.<List<SearchConsoleResponseDto>>builder()
.result(list)
.resultCode(SuccessCode.SELECT_SUCCESS.getStatus())
.resultMsg(SuccessCode.SELECT_SUCCESS.getMessage())
.build();
return new ResponseEntity<>(arw, HttpStatus.OK);
} catch (Exception e) {
log.error("Search Console API 호출 실패: ", e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
6. 결과 확인
💡 결과 확인
- HTTP Client를 이용하여 아래와 같은 결과값을 얻었습니다.

6.1. 결과화면 : 키워드 분석

6.2. 결과화면 : 기기별 성과

6.3. 결과화면 : 국가별 트래픽

오늘도 감사합니다. 😀
