[시리즈 3부] 오늘부터 적용하는 Canonical 태그 완벽 구현법|올씽블로그

prfparkst
By -
0

[시리즈 3부] 오늘부터 적용하는 Canonical 태그 완벽 구현법

"코딩 몰라도 10분 안에 끝낼 수 있습니다.
복사-붙여넣기만 하면 됩니다."


시작하기 전: 당신에게 필요한 것은 단 3가지

필요 없는 것:

  • 프로그래밍 지식
  • 서버 관리 경험
  • 비싼 SEO 도구

필요한 것:

  • 사이트 관리자 권한 (WordPress, Shopify 등)
  • 복사-붙여넣기 능력
  • 10분의 시간

이 글을 끝까지 읽으면: 오늘 당장 당신의 사이트에 Canonical 태그를 적용하고, 내일부터 구글이 당신이 원하는 페이지를 보여주기 시작합니다.


Part 1: 기본 원칙 - 모든 플랫폼 공통

📋 Canonical 태그의 기본 문법

<link rel="canonical" href="https://yoursite.com/page-url/" />

5가지 절대 규칙:

규칙 1: 항상 절대 경로 (Absolute URL)

<!-- ✅ 올바름 -->
<link rel="canonical" href="https://example.com/products/shoes/" />

<!-- ❌ 틀림 -->
<link rel="canonical" href="/products/shoes/" />
<link rel="canonical" href="products/shoes/" />

이유: 크롤러가 URL을 잘못 해석할 위험 제거


규칙 2: www와 프로토콜 일관성

<!-- 사이트가 www 사용한다면 -->
<link rel="canonical" href="https://www.example.com/page/" />

<!-- 사이트가 non-www 사용한다면 -->
<link rel="canonical" href="https://example.com/page/" />

확인 방법: 브라우저에서 yoursite.com 입력 → 주소창 확인


규칙 3: 후행 슬래시(/) 일관성

<!-- 사이트가 / 사용한다면 -->
<link rel="canonical" href="https://example.com/page/" />

<!-- 사이트가 / 안 쓴다면 -->
<link rel="canonical" href="https://example.com/page" />

주의: 혼용 금지!

  • https://site.com/pagehttps://site.com/page/ (구글은 다른 페이지로 인식)

규칙 4: <head> 섹션 내 위치

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>페이지 제목</title>
    
    <!-- ✅ 여기에 위치 -->
    <link rel="canonical" href="https://example.com/page/" />
    
    <meta name="description" content="...">
</head>
<body>
    <!-- ❌ body에 넣으면 무효 -->
</body>
</html>

규칙 5: 페이지당 하나만

<!-- ❌ 절대 안 됨 -->
<link rel="canonical" href="https://example.com/page-a/" />
<link rel="canonical" href="https://example.com/page-b/" />

<!-- ✅ 하나만 -->
<link rel="canonical" href="https://example.com/page-a/" />

Part 2: 플랫폼별 실전 구현 (복사-붙여넣기 가이드)

🔷 WordPress (전 세계 43% 웹사이트 사용)

방법 1: Yoast SEO 플러그인 (가장 쉬움)

STEP 1: 플러그인 설치

WordPress 관리자 → 플러그인 → 새로 추가 → "Yoast SEO" 검색 → 설치 및 활성화

STEP 2: 자동 설정 (완료!)

Yoast SEO는 자동으로 모든 페이지에 canonical 추가
확인: 페이지 소스 보기 (Ctrl+U) → <link rel="canonical" 검색

STEP 3: 수동 조정 (필요시)

게시물/페이지 편집 → 하단 Yoast SEO 메타박스 → 고급 탭 → Canonical URL 입력

예시:

중복 페이지: /red-shoes
원본 페이지: /shoes

→ /red-shoes 편집 시 Canonical URL에 입력:
https://yoursite.com/shoes

방법 2: All in One SEO 플러그인

설치 후 자동 활성화
수동 조정: 게시물 편집 → AIOSEO Settings → Canonical URL

방법 3: 테마 functions.php (개발자용)

경로: wp-content/themes/your-theme/functions.php

// 모든 페이지에 self-referencing canonical 추가
function add_canonical_tag() {
    if (is_singular()) {
        echo '<link rel="canonical" href="' . get_permalink() . '" />' . "\n";
    }
}
add_action('wp_head', 'add_canonical_tag', 1);

적용 후 확인:

페이지 새로고침 → 소스 보기 (Ctrl+U) → canonical 검색

방법 4: 특정 페이지만 수동 추가

Custom HTML 블록 사용 (WordPress 5.0+):

페이지 편집 → + 버튼 → "Custom HTML" 블록 추가 → 상단에 배치

입력:
<link rel="canonical" href="https://yoursite.com/target-page/" />

⚠️ 주의: 이 방법은 <head>가 아닌 <body>에 삽입되므로 비권장


🔶 Shopify (이커머스 1위)

기본 설정: 자동 포함 (확인만 필요)

Shopify는 기본적으로 모든 페이지에 canonical 자동 추가

확인 방법:

1. 상점 방문 → 아무 상품 페이지
2. 우클릭 → 페이지 소스 보기
3. Ctrl+F → "canonical" 검색

예상 결과:

<link rel="canonical" href="https://yourstore.myshopify.com/products/product-name">

커스텀 설정: 특정 페이지만 수동 지정

STEP 1: 테마 편집

온라인 스토어 → 테마 → 작업 → 코드 편집

STEP 2: theme.liquid 파일 열기

Layout → theme.liquid

STEP 3: <head> 섹션 찾기

<head>
  {{ content_for_header }}
  
  <!-- 여기에 추가 -->
  {% if template == 'product' %}
    <link rel="canonical" href="{{ shop.url }}{{ product.url }}" />
  {% endif %}
  
</head>

변형 상품 처리 (핵심!)

문제: 색상/사이즈별 URL이 다름

빨간색: /products/tshirt?variant=123
파란색: /products/tshirt?variant=456

해결: 모두 메인 상품 페이지로

{% if product %}
  <link rel="canonical" href="{{ shop.url }}/products/{{ product.handle }}" />
{% endif %}

결과: 모든 변형이 /products/tshirt를 가리킴


🔹 HTML/CSS 정적 사이트

모든 페이지에 직접 추가

index.html:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>홈페이지</title>
    <link rel="canonical" href="https://yoursite.com/" />
</head>
<body>
    <!-- 콘텐츠 -->
</body>
</html>

about.html:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>회사 소개</title>
    <link rel="canonical" href="https://yoursite.com/about.html" />
</head>
<body>
    <!-- 콘텐츠 -->
</body>
</html>

⚛️ React (Next.js, Gatsby)

Next.js (App Router - Next.js 13+)

app/layout.tsx 또는 app/page.tsx:

import { Metadata } from 'next'

export const metadata: Metadata = {
  alternates: {
    canonical: 'https://yoursite.com/current-page',
  },
}

export default function Page() {
  return <div>콘텐츠</div>
}

Next.js (Pages Router - Next.js 12 이하)

pages/_app.tsx 또는 개별 페이지:

import Head from 'next/head'

export default function Page() {
  return (
    <>
      <Head>
        <link rel="canonical" href="https://yoursite.com/page" />
      </Head>
      <div>콘텐츠</div>
    </>
  )
}

동적 URL 처리

import { useRouter } from 'next/router'
import Head from 'next/head'

export default function Page() {
  const router = useRouter()
  const canonicalUrl = `https://yoursite.com${router.asPath}`
  
  return (
    <>
      <Head>
        <link rel="canonical" href={canonicalUrl} />
      </Head>
      <div>콘텐츠</div>
    </>
  )
}

Gatsby

gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-plugin-canonical-urls',
      options: {
        siteUrl: 'https://yoursite.com',
      },
    },
  ],
}

수동 추가 (개별 페이지):

import { Helmet } from 'react-helmet'

export default function Page() {
  return (
    <>
      <Helmet>
        <link rel="canonical" href="https://yoursite.com/page" />
      </Helmet>
      <div>콘텐츠</div>
    </>
  )
}

🅰️ Angular

app.component.ts:

import { Component, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  constructor(private meta: Meta) {}

  ngOnInit() {
    this.meta.updateTag({
      rel: 'canonical',
      href: 'https://yoursite.com/current-page'
    });
  }
}

🟢 Vue.js (Nuxt)

nuxt.config.js:

export default {
  head: {
    link: [
      { rel: 'canonical', href: 'https://yoursite.com/' }
    ]
  }
}

개별 페이지 (pages/about.vue):

<script>
export default {
  head() {
    return {
      link: [
        { rel: 'canonical', href: 'https://yoursite.com/about' }
      ]
    }
  }
}
</script>

🛒 WooCommerce (WordPress + 이커머스)

Yoast SEO 사용 시 (자동):

Yoast가 자동으로 처리
상품 변형도 자동 처리

수동 설정 (functions.php):

// 상품 변형 페이지를 메인 상품으로 canonical 설정
add_action('wp_head', 'woocommerce_canonical_fix');
function woocommerce_canonical_fix() {
    if (is_product()) {
        global $post;
        echo '<link rel="canonical" href="' . get_permalink($post->ID) . '" />';
    }
}

🎨 Wix

내장 기능 (자동):

Wix는 자동으로 canonical 추가
확인: 페이지 설정 → SEO (Google) → 고급 설정

수동 조정:

1. 페이지 → 설정 아이콘
2. SEO (Google)
3. 고급 설정 → Canonical URL 입력

🟦 Squarespace

자동 포함 (7.1 버전):

모든 페이지에 자동 추가

수동 확인:

설정 → 고급 → 코드 삽입 → 헤더
(일반적으로 건드릴 필요 없음)

Part 3: Self-Referencing Canonical (필수 개념)

🔄 "자기 자신을 가리키는" Canonical

개념

<!-- URL: https://site.com/page-a -->
<link rel="canonical" href="https://site.com/page-a" />

의미: "이 페이지가 대표 버전입니다"


왜 필요한가?

케이스: 파라미터 URL 자동 생성

사용자 A: https://site.com/page-a 방문
사용자 B: https://site.com/page-a?utm_source=facebook 방문

Self-referencing canonical이 있으면:

<!-- 두 URL 모두 이 태그 포함 -->
<link rel="canonical" href="https://site.com/page-a" />

→ 구글: "둘 다 /page-a를 가리키네. /page-a를 인덱싱하자"

없으면:

→ 구글: "두 URL이 다르네? 둘 다 인덱싱? 아니면 하나만? 고민..."
→ 임의 선택 또는 둘 다 순위 하락

베스트 프랙티스: 모든 페이지에 넣기

홈페이지: https://site.com/
→ <link rel="canonical" href="https://site.com/" />

블로그: https://site.com/blog/seo-guide/
→ <link rel="canonical" href="https://site.com/blog/seo-guide/" />

상품: https://site.com/products/shoes/
→ <link rel="canonical" href="https://site.com/products/shoes/" />

John Mueller (Google):

"Adding self-referencing canonicals to all pages is a best practice. It helps us understand your preference clearly."


Part 4: 특수 시나리오 구현

📄 시나리오 1: 파라미터 URL 처리

문제:

원본: /products/shoes
정렬: /products/shoes?sort=price
필터: /products/shoes?color=red&size=large

해결 1: Canonical 태그

<!-- 모든 변형 페이지에 -->
<link rel="canonical" href="https://site.com/products/shoes" />

해결 2: Google Search Console (보조)

1. Search Console → 설정 → 크롤링
2. URL 파라미터
3. 추가: sort, color, size
4. 설정: "콘텐츠 변경 안 함"

📱 시나리오 2: 모바일 별도 버전 (M-dot)

구조:

데스크톱: https://example.com/page
모바일: https://m.example.com/page

데스크톱 페이지:

<link rel="canonical" href="https://example.com/page" />
<link rel="alternate" media="only screen and (max-width: 640px)" 
      href="https://m.example.com/page" />

모바일 페이지:

<link rel="canonical" href="https://example.com/page" />

핵심: 모바일은 데스크톱을 canonical로 지정


시나리오 3: AMP 페이지

구조:

일반: https://site.com/article
AMP: https://site.com/article/amp

일반 페이지:

<link rel="canonical" href="https://site.com/article" />
<link rel="amphtml" href="https://site.com/article/amp" />

AMP 페이지:

<link rel="canonical" href="https://site.com/article" />

🔢 시나리오 4: 페이지네이션

잘못된 방법 (절대 금지):

<!-- 모든 페이지가 1페이지를 가리킴 (❌) -->
<!-- 2페이지 -->
<link rel="canonical" href="https://site.com/blog/" />

<!-- 3페이지 -->
<link rel="canonical" href="https://site.com/blog/" />

올바른 방법:

<!-- 1페이지 -->
<link rel="canonical" href="https://site.com/blog/" />
<link rel="next" href="https://site.com/blog/page/2/" />

<!-- 2페이지 -->
<link rel="canonical" href="https://site.com/blog/page/2/" />
<link rel="prev" href="https://site.com/blog/" />
<link rel="next" href="https://site.com/blog/page/3/" />

<!-- 마지막 페이지 -->
<link rel="canonical" href="https://site.com/blog/page/10/" />
<link rel="prev" href="https://site.com/blog/page/9/" />

🌍 시나리오 5: 다국어 사이트

구조:

한국어: https://site.com/ko/product
영어: https://site.com/en/product
일본어: https://site.com/ja/product

한국어 페이지:

<link rel="canonical" href="https://site.com/ko/product" />
<link rel="alternate" hreflang="ko" href="https://site.com/ko/product" />
<link rel="alternate" hreflang="en" href="https://site.com/en/product" />
<link rel="alternate" hreflang="ja" href="https://site.com/ja/product" />
<link rel="alternate" hreflang="x-default" href="https://site.com/en/product" />

영어/일본어 페이지도 동일 패턴

핵심:

  • 각 언어 페이지는 자기 자신을 canonical로
  • hreflang으로 언어 관계 표시

Part 5: 검증 및 테스트 (필수!)

STEP 1: 브라우저 수동 확인 (1분)

1. 페이지 방문
2. 우클릭 → 페이지 소스 보기 (Ctrl+U)
3. Ctrl+F → "canonical" 검색

체크 포인트:

  • [ ] <link rel="canonical" 존재?
  • [ ] href가 절대 경로 (https://...)?
  • [ ] URL이 현재 페이지와 일치? (self-referencing)
  • [ ] <head> 섹션 안에 위치?
  • [ ] 1개만 존재?

STEP 2: 개발자 도구 확인 (2분)

F12 → Console 탭

입력:
document.querySelector('link[rel="canonical"]').href

정상 결과:

"https://yoursite.com/current-page/"

오류 결과:

null (태그 없음)
"undefined"

STEP 3: Google Search Console (5분)

1. Search Console 로그인
2. URL 검사 도구
3. 테스트할 URL 입력
4. "색인 생성된 페이지 보기"

확인 사항:

  • 사용자가 지정한 표준 페이지: 당신이 설정한 canonical
  • Google이 선택한 표준 페이지: 구글이 실제 선택한 URL

이상적 상태: 둘이 동일

문제 상태: 둘이 다름 → 구글이 당신의 canonical 무시 중 → 원인: 5% 함정 케이스 (2부 참고)


STEP 4: 대량 검증 - Screaming Frog (10분)

무료 버전 (500 URL까지):

1. Screaming Frog 다운로드 설치
2. 사이트 URL 입력 → Start
3. Internal 탭 → Canonical 컬럼

필터 활용:

Canonical > Filter > "Missing"
→ canonical 없는 페이지 리스트

Canonical > Filter > "Canonicalised"
→ 다른 페이지를 가리키는 페이지들

Canonical > Filter > "Self-referencing"
→ 정상 (자기 자신 가리킴)

경고 신호:

  • Missing > 전체의 30%
  • 404/리다이렉트 페이지를 가리키는 canonical
  • 여러 페이지가 동일한 canonical 지정 (확인 필요)

STEP 5: 실시간 테스트 도구

구글 리치 결과 테스트

https://search.google.com/test/rich-results

URL 입력 → 테스트
→ HTML 탭에서 canonical 확인

Part 6: 일반적인 실수와 디버깅

🐛 실수 1: 상대 경로 사용

문제:

<link rel="canonical" href="/products/shoes" />

증상: Google Search Console에서 "표준 페이지 불일치"

해결:

<link rel="canonical" href="https://site.com/products/shoes" />

🐛 실수 2: Canonical이 404 페이지

문제:

<link rel="canonical" href="https://site.com/deleted-page" />

증상: 구글이 canonical 무시, 자체 선택

확인 방법:

Screaming Frog → Response Codes 탭
Canonical URL 열 확인
→ 404 있으면 즉시 수정

해결: 살아있는 페이지로 변경


🐛 실수 3: HTTPS/HTTP 혼용

문제:

<!-- 사이트는 HTTPS인데 canonical은 HTTP -->
<link rel="canonical" href="http://site.com/page" />

증상: 보안 경고, SEO 신호 약화

해결: 일관되게 HTTPS 사용


🐛 실수 4: 여러 개 태그

문제:

<!-- 플러그인이 자동 생성 -->
<link rel="canonical" href="https://site.com/A" />

<!-- 수동으로 추가 -->
<link rel="canonical" href="https://site.com/B" />

증상: 구글이 첫 번째만 인식

확인:

// 개발자 도구 Console
document.querySelectorAll('link[rel="canonical"]').length

결과가 2 이상이면 문제

해결: 중복 제거


🐛 실수 5: Noindex + Canonical

문제:

<meta name="robots" content="noindex" />
<link rel="canonical" href="https://site.com/page" />

증상: Canonical 무시됨

해결: 둘 중 하나만 선택


Part 7: 즉시 적용 체크리스트

📝 10분 Quick Start 가이드

[2분] 환경 확인

  • [ ] 내 사이트 플랫폼 확인 (WordPress? Shopify? 기타?)
  • [ ] 관리자 로그인 권한 확인

[5분] 핵심 페이지 적용

  • [ ] 홈페이지에 canonical 추가
  • [ ] 주력 상품/글 Top 3에 canonical 추가
  • [ ] 카테고리 페이지에 canonical 추가

[3분] 검증

  • [ ] 페이지 소스 보기로 확인
  • [ ] 개발자 도구 Console로 확인
  • [ ] 모바일에서도 확인

🎯 30분 전체 사이트 적용

[10분] 자동화 설정

  • WordPress: Yoast SEO 설치 및 활성화
  • Shopify: 기본 설정 확인
  • Next.js: Head 컴포넌트에 추가
  • 기타: 플랫폼별 방법 적용

[10분] 특수 케이스 처리

  • [ ] 파라미터 URL 확인 및 canonical 설정
  • [ ] 페이지네이션 확인
  • [ ] 중복 콘텐츠 페이지 찾아서 canonical 설정

[10분] 전체 검증

  • [ ] Screaming Frog 크롤
  • [ ] Missing 페이지 모두 수정
  • [ ] Google Search Console URL 검사 (주요 페이지 5개)

Part 8: 성공 측정

📈 1주일 후 확인 사항

Google Search Console:

색인 생성 > 페이지

Before:
- "중복, Google이 선택": 150개
- "중복, 사용자가 선택": 50개

After 목표:
- "중복, Google이 선택": 0개
- "중복, 사용자가 선택": 200개

📈 1개월 후 기대 효과

트래픽 변화:

Google Analytics → 획득 → 전체 트래픽 → 채널

오가닉 검색 트래픽 증가 예상: 20~40%

순위 변화:

Google Search Console → 실적

평균 게재 순위 개선 예상: 2~5위 상승

다음 편 예고

[4부] 고급 시나리오별 Canonical 전략

"이커머스 천 개 상품, 다국어 사이트, AMP...
복잡한 상황일수록 Canonical이 더 중요합니다."

  • 다국어 사이트: hreflang과 canonical의 완벽 조합

Tags:

댓글 쓰기

0댓글

댓글 쓰기 (0)