남의 웹사이트 기술 스택과 브랜드 컬러, 브라우저 콘솔로 알아내는 법
확장 프로그램 없이 script 목록·전역 객체·meta generator·컬러 빈도로 사이트를 실측하는 복붙용 JS 스니펫 모음.
클라이언트가 URL 하나를 던지면서 “이 사이트처럼 해주세요”라고 할 때가 있습니다. 문제는 그 “이 사이트처럼”이 정확히 무엇을 가리키는지 아무도 모른다는 겁니다. 스크롤할 때 따라오는 부드러운 관성일 수도 있고, 특정 주황색일 수도 있고, 그냥 폰트가 마음에 든 것일 수도 있습니다.
저는 레퍼런스 사이트를 위키에 저장하는 작업을 반복하면서 이 문제를 자주 만났습니다. 처음엔 풀페이지 스크린샷만 찍어 뒀는데, 정작 나중에 그 파일을 열어 보면 “뭘 훔쳐와야 하는지”가 하나도 안 남아 있었습니다. 스크린샷에는 스크롤 애니메이션도, 정확한 컬러 값도, 어떤 라이브러리를 썼는지도 기록되지 않으니까요. 게다가 GSAP·Lenis 같은 모션 라이브러리를 무겁게 쓰는 사이트는 자동 스크린샷 자체가 타임아웃으로 실패하는 일이 잦았습니다.
그래서 방식을 바꿨습니다. 스크린샷은 “분위기”를 남기는 용도로만 쓰고, 기술적인 사실은 브라우저 콘솔에서 직접 실측해서 텍스트로 남깁니다. 설치할 것도 없고, 결과가 텍스트라 그대로 문서에 붙일 수 있습니다. 아래는 지금까지 반복해서 쓰면서 정리된 스니펫들입니다.
실측은 네 가지만 봅니다
| 무엇을 | 어떻게 | 알 수 있는 것 |
|---|---|---|
| 로드하는 스크립트 | script[src] 목록 | CDN, 분석 도구, 빌드 방식 |
| 실행 중인 라이브러리 | 전역 객체(window.gsap 등) | 모션·슬라이더·프레임워크 |
| CMS·테마 | meta[name=generator], wp-content 경로 | 워드프레스인지, 어떤 테마인지 |
| 브랜드 컬러 | getComputedStyle 빈도 분석 | 실제로 화면을 지배하는 색 |
순서대로 하나씩 보겠습니다. 전부 개발자도구(F12) → Console 탭에 붙여넣고 엔터만 치면 됩니다.
1. 스크립트 목록 — 무엇을 불러오고 있나
가장 먼저 보는 건 외부에서 뭘 끌어오는지입니다. 호스트와 파일명만 뽑아서 표로 보면 CDN에서 통째로 가져오는지, 자체 번들인지 한눈에 갈립니다.
const srcs = [...document.querySelectorAll('script[src]')].map(s => s.src);
console.log('스크립트', srcs.length, '개');
console.table(srcs.map(u => {
const { hostname, pathname } = new URL(u);
return { host: hostname, file: pathname.split('/').pop() };
}));
cdnjs, unpkg, jsdelivr 호스트가 보이면 그 파일명이 곧 라이브러리 이름입니다. 반대로 전부 자기 도메인이고 파일명이 index-a3f9c1.js 같은 해시라면 Vite·webpack으로 번들한 사이트라는 뜻이고, 이 경우 파일명만으로는 아무것도 알 수 없습니다. 그래서 다음 단계가 필요합니다.
2. 전역 객체 탐지 — 실제로 돌고 있는 라이브러리
파일명이 아니라 런타임에 살아 있는 객체를 확인하는 방법입니다. 라이브러리가 window에 자기 이름을 붙이는 성질을 이용합니다.
const libs = {
gsap: window.gsap,
ScrollTrigger: window.ScrollTrigger,
Lenis: window.Lenis,
Swiper: window.Swiper,
jQuery: window.jQuery,
THREE: window.THREE,
barba: window.barba,
AOS: window.AOS,
Alpine: window.Alpine,
};
Object.entries(libs)
.filter(([, v]) => v)
.forEach(([name, v]) => {
const ver = v.version || v.VERSION || (v.fn && v.fn.jquery) || '(버전 미노출)';
console.log('[detected]', name, ver);
});
프레임워크는 전역 객체 대신 DOM에 흔적을 남기는 경우가 많아서 따로 봅니다.
console.table({
'Next.js': !!window.__NEXT_DATA__ || !!document.querySelector('#__next'),
'Nuxt': !!window.__NUXT__,
'Gatsby': !!window.___gatsby,
'Astro': !!document.querySelector('astro-island, [class*="astro-"]'),
'React(dev)':!!document.querySelector('[data-reactroot]'),
'Svelte': !!document.querySelector('[class*="svelte-"]'),
});
주의: 스크롤해야 로드되는 라이브러리가 있습니다. 한 번 페이지 끝까지 내렸다가 다시 실행하면 결과가 달라지는 경우가 실제로 있으니, 초기 화면에서만 돌리고 결론 내리지 마세요.
3. CMS와 테마 — 워드프레스는 이걸로 다 나옵니다
const gen = document.querySelector('meta[name="generator"]');
console.log('generator:', gen ? gen.content : '없음');
const urls = [...document.querySelectorAll('link[href], script[src]')]
.map(el => el.href || el.src);
const pick = (kind) => [...new Set(
urls.filter(u => u.includes(`/wp-content/${kind}/`))
.map(u => u.split(`/wp-content/${kind}/`)[1].split('/')[0])
)];
console.log('테마:', pick('themes'));
console.log('플러그인:', pick('plugins'));
generator에 버전까지 그대로 노출하는 사이트가 의외로 많습니다. 플러그인 목록이 나오면 그 사이트가 폼·슬라이더·SEO를 각각 무엇으로 처리했는지까지 그대로 드러납니다.
한 가지 덧붙이면, 쇼핑몰 솔루션 미리보기처럼 로그인 벽 뒤에 있어 보이는 페이지도 실제로는 iframe만 벗기면 되는 경우가 있습니다. 카페24 디자인 미리보기가 그런 사례였는데, 겉보기와 달리 로그인이 필요 없고 iframe의 src에 진짜 데모 주소가 들어 있었습니다.
[...document.querySelectorAll('iframe')].forEach(f => console.log(f.src));
여기서 나온 주소로 직접 접속하면 그 다음부터는 평범한 페이지처럼 실측할 수 있습니다.
4. 컬러 빈도 분석 — 브랜드 액센트 뽑아내기
스포이드로 몇 군데 찍는 것보다, 페이지 전체 요소의 계산된 색을 모아 빈도순으로 정렬하는 편이 정확합니다. 핵심은 회색조를 제외하는 것입니다. 그렇게 안 하면 흰색·검정·회색이 상위권을 전부 차지해서 아무 정보도 안 남습니다.
const count = {};
const props = ['color', 'backgroundColor', 'borderTopColor', 'fill'];
for (const el of document.querySelectorAll('*')) {
const cs = getComputedStyle(el);
for (const p of props) {
const m = (cs[p] || '').match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/);
if (!m) continue;
const [r, g, b] = [+m[1], +m[2], +m[3]];
const a = m[4] === undefined ? 1 : +m[4];
if (a < 0.1) continue; // 투명 제외
if (Math.max(r, g, b) - Math.min(r, g, b) < 25) continue; // 회색조 제외
const hex = '#' + [r, g, b].map(n => n.toString(16).padStart(2, '0')).join('');
count[hex] = (count[hex] || 0) + 1;
}
}
Object.entries(count)
.sort((a, b) => b[1] - a[1])
.slice(0, 12)
.forEach(([hex, n]) => console.log(
`%c %c ${hex} × ${n}`,
`background:${hex};padding:6px;border-radius:3px`, ''
));
%c 서식 덕분에 콘솔에 실제 색 칩이 같이 찍혀서, 값과 눈으로 본 인상을 한 번에 대조할 수 있습니다. 채도 기준값(25)은 상황에 맞게 조절하세요. 값을 올리면 진짜 강한 액센트만 남고, 내리면 파스텔 톤도 잡힙니다.
폰트까지 보고 싶다면
폰트는 CSS 값과 실제 다운로드된 파일 두 가지를 같이 봐야 정확합니다.
// 실제 적용된 폰트 스택
const fonts = {};
document.querySelectorAll('h1,h2,h3,p,a,button,li').forEach(el => {
const f = getComputedStyle(el).fontFamily;
fonts[f] = (fonts[f] || 0) + 1;
});
console.table(fonts);
// 실제로 받아온 웹폰트 파일
performance.getEntriesByType('resource')
.filter(r => /\.(woff2?|otf|ttf)(\?|$)/.test(r.name))
.forEach(r => console.log(r.name.split('/').pop()));
CSS에는 다섯 개짜리 폰트 스택이 걸려 있어도 실제로 내려받은 파일은 하나뿐인 경우가 흔합니다. 그 하나가 진짜 그 사이트의 폰트입니다.
점수: 8.7
좋은 점
- 설치·로그인·권한 승인이 전혀 필요 없습니다. 브라우저만 있으면 어디서든 동일하게 동작합니다
- 결과가 텍스트라 그대로 문서에 붙여 기록으로 남길 수 있습니다. 스크린샷과 달리 검색도 됩니다
- 애니메이션이 무거워 자동 스크린샷이 타임아웃되는 사이트에서도 실측은 그대로 됩니다. 저에겐 이게 가장 실용적인 이유였습니다
- 컬러 hex 값이나 실제 적용된 폰트처럼, 눈대중이나 요약 도구로는 놓치기 쉬운 정확한 수치를 얻습니다
아쉬운 점
- 번들된 사이트에서는 전역 객체 탐지가 잘 안 먹힙니다. GSAP을 쓰고 있어도 모듈로 import 했다면
window.gsap은undefined입니다. 이때는 네트워크 탭이나 소스맵을 봐야 하는데 손이 많이 갑니다 - 컬러 빈도는 “많이 쓰인 색”이지 “브랜드 색”이 아닙니다. 넓은 푸터 배경 하나가 1위로 올라오기도 하므로 사람 눈으로 한 번 걸러야 합니다
- 일러스트·사진·전반적인 무드처럼 시각적인 인상은 실측으로 전혀 잡히지 않습니다. 이 부분은 결국 스크린샷과 화면녹화를 따로 남겨야 합니다
- 스크롤 이후에 로드되는 요소는 초기 실행 결과에 안 들어옵니다. 최소 두 번은 돌려야 합니다
이럴 때 쓰세요: 레퍼런스 사이트를 “느낌”이 아니라 재현 가능한 정보로 남겨야 할 때, 그리고 견적·기술 검토 단계에서 상대 사이트의 구현 난이도를 가늠해야 할 때.
확장 프로그램 대신 콘솔을 쓰는 이유
Wappalyzer 같은 기술 스택 탐지 확장 프로그램도 있고, 라이브러리 이름만 빠르게 확인할 때는 그쪽이 편합니다. 다만 확장 프로그램은 정해진 항목만 알려주고, 컬러 빈도나 실제 적용 폰트처럼 제가 필요한 값은 안 나옵니다. 스니펫은 필요한 대로 고쳐 쓸 수 있고, 결과를 그대로 복사해 기록으로 옮길 수 있다는 점이 다릅니다. 둘 중 하나를 고르는 문제라기보단, 확장 프로그램으로 큰 그림을 보고 세부는 콘솔로 재는 쪽이 실용적입니다.
주의사항
- 여기서 다루는 건 브라우저가 이미 내려받은 공개된 프론트엔드 정보뿐입니다. 인증이 필요한 영역을 우회하는 방법이 아닙니다.
- 로그인이 필요한 사이트는 본인 계정으로 직접 로그인한 세션에서만 보세요. 남에게, 혹은 자동화 도구에 계정 비밀번호를 대신 입력하게 하지 마세요.
- 실측으로 가져올 것은 아이디어와 기법이지 코드나 이미지 에셋이 아닙니다. “이 사이트는 스크롤 관성에 Lenis를 썼구나”를 배우는 것과 남의 CSS를 복사하는 것은 완전히 다른 일입니다.