Contents
Pexels API キー取得と認証
このセクションでは、まず公式サイトから API キーを取得する手順を確認し、その後 Bearer トークン方式での認証方法を具体例とともに紹介します。キーはプロジェクトごとに一意に管理し、不正利用を防止することが重要です。
API キーの取得手順
- Pexels 公式サイトの API ページ(https://www.pexels.com/ja-jp/api/)へアクセスします。
- 「Get Started」ボタンをクリックし、Pexels アカウントでログインします。
- ダッシュボードに表示される 32 桁の文字列 が API キーです。取得は自動審査のため即時に完了します。
安全な保管方法
- 環境変数(例:PEXELS_API_KEY)やサーバー側シークレットストアを利用する。
- キーをコードベースにハードコーディングしない。
- 共有リポジトリへ誤ってプッシュした場合は、直ちにキーを再発行してください。
認証方法(Bearer トークン)
Pexels API は HTTP Authorization ヘッダー に Bearer <API_KEY> を付与するだけで認証が完了します。以下の例は、主要なプログラミング言語・ライブラリで共通して使用できる記述です。
|
1 2 |
Authorization: Bearer {YOUR_API_KEY} |
- JavaScript (fetch)
js
fetch(url, { headers: { Authorization:Bearer ${API_KEY}} }) - Python (requests)
python
requests.get(url, headers={"Authorization": f"Bearer {API_KEY}"}) - Node.js (axios)
js
axios.get(url, { headers: { Authorization:Bearer ${apiKey}} })
認証ヘッダーが欠如したリクエストは 401 Unauthorized が返されるため、必ずキーを付与していることをテストしてください。
エンドポイントとパラメータ解説
ここでは写真検索・動画検索それぞれのエンドポイントと主要パラメータを整理し、実際にリクエスト URL を構築する手順を示します。
写真検索エンドポイント /v1/search
GET https://api.pexels.com/v1/search に対してクエリパラメータを付与すると、条件に合致した画像の一覧が取得できます。
| パラメータ | 例 | 説明(最大文字数・範囲) |
|---|---|---|
query |
nature |
キーワード(必須)。日本語・英語どちらでも可。 |
orientation |
landscape |
portrait, square から選択。省略時は全方向。 |
size |
large |
small, medium, large のいずれか。 |
locale |
ja-JP |
言語・地域コード(検索結果の説明文に影響)。 |
per_page |
15 |
1 回の取得件数。最大 80 件まで指定可能。 |
page |
2 |
ページ番号(0 起算ではなく 1 起算)。 |
例:日本語で「桜」かつ横長画像を 10 件取得する場合
https://api.pexels.com/v1/search?query=桜&orientation=landscape&per_page=10&locale=ja-JP
動画検索エンドポイント /videos/search
動画は GET https://api.pexels.com/videos/search にリクエストします。写真検索と似た構造ですが、サイズ指定やページングに違いがあります。
| パラメータ | 例 | 説明 |
|---|---|---|
query |
city timelapse |
キーワード(必須)。 |
orientation |
landscape |
portrait, square が利用可。 |
size |
medium |
large, small も選択可能。 |
min_width |
1280 |
ピクセル単位の最小横幅。省略時はデフォルト 640px。 |
per_page |
12 |
最大 30 件まで取得可能。 |
page |
1 |
ページ番号。 |
レートリミット(公式情報)
2024 年 10 月に更新された Pexels の公式ドキュメント(https://www.pexels.com/ja-jp/api/)によると、無料プランでは 1 時間あたり 200 リクエストが上限です。写真検索・動画検索ともにこのリミットが適用されます。大量取得が必要な場合は以下を実装してください。
- キャッシュ:同一キーワード・ページの結果はローカルまたは CDN に保存し、再利用する。
- バックオフ戦略:
429 Too Many Requestsが返されたらRetry-Afterヘッダーの指示秒数だけ待機して再試行。
レスポンス構造とエラーハンドリング
この章では、API が返す JSON の主要フィールドを解説し、ステータスコード別に推奨される対策をまとめます。実装時のデバッグやログ出力に役立ててください。
JSON フィールドの概要(写真)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "total_results": 3456, "page": 1, "per_page": 15, "photos": [ { "id": 2014422, "url": "https://www.pexels.com/photo/...", "photographer": "John Doe", "src": { "original": ".../photo-2014422-original.jpeg", "large2x": ".../photo-2014422-large_2x.jpeg", "large": ".../photo-2014422-large.jpeg", "medium": ".../photo-2014422-medium.jpeg", "small": ".../photo-2014422-small.jpeg" } } ] } |
| フィールド | 内容・利用シーン |
|---|---|
id |
画像を一意に特定できる ID。キャッシュキーとして有用。 |
url |
Pexels の公式ページ URL(クレジット表示や著作者確認に使用)。 |
photographer |
撮影者名。任意で「Photo by ○○ on Pexels」と記載可。 |
src |
複数サイズの画像 URL が格納。medium はバランスが良く、original は最高画質。 |
動画レスポンス(抜粋)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "total_results": 124, "page": 1, "per_page": 12, "videos": [ { "id": 12345, "url": "https://www.pexels.com/video/...", "image": ".../preview.jpg", "duration": 15, "video_files": [ { "width": 1920, "height": 1080, "link": ".../video-1920.mp4", "file_type": "mp4" }, { "width": 1280, "height": 720, "link": ".../video-1280.mp4", "file_type": "mp4" } ] } ] } |
主なステータスコードと対策
| コード | 意味 | 主な原因 | 推奨対策 |
|---|---|---|---|
| 401 | Unauthorized | Authorization ヘッダー欠如、またはキーが無効 | キーを環境変数から正しく取得し、Bearer 形式で送信 |
| 403 | Forbidden | アカウントの利用制限やロゴ使用違反 | Pexels の利用規約(公式ページ)を再確認し、キー共有を停止 |
| 429 | Too Many Requests | 1 時間あたり 200 リクエスト上限超過 | Retry-After ヘッダーで待機し、指数的バックオフとキャッシュでリクエスト削減 |
| 500 系列 | サーバー内部エラー | Pexels 側の一時障害 | 再試行ロジックを実装し、数回失敗したらアラート通知 |
エラーレスポンスは通常 { "error": "Message" } という JSON 形式です。ログに status, error.message, requestId(存在すれば) を残すとトラブルシューティングが容易になります。
実装例とキャッシュ戦略
本節では、代表的な言語・フレームワーク別のサンプルコードを示しつつ、レートリミット回避のためのキャッシュ手法も解説します。実際に動作させる際は、API キーをハードコーディングせず環境変数から取得してください。
JavaScript(fetch)サンプル
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<div id="gallery"></div> <script> const API_KEY = (() => { // 本番ではサーバープロキシ経由で取得することを推奨 return 'YOUR_API_KEY'; })(); async function searchPhotos(query) { const url = new URL('https://api.pexels.com/v1/search'); url.searchParams.set('query', query); url.searchParams.set('per_page', 9); url.searchParams.set('orientation', 'landscape'); const response = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } }); if (!response.ok) { console.error(`Error ${response.status}`); return; } const data = await response.json(); renderGallery(data.photos); } function renderGallery(photos) { const container = document.getElementById('gallery'); container.innerHTML = photos.map(p => ` <a href="${p.url}" target="_blank" rel="noopener"> <img src="${p.src.medium}" alt="${p.photographer}"> </a> `).join(''); } // 初回検索(デモ用) searchPhotos('東京 スカイツリー'); </script> |
キャッシュポイント(ブラウザ)
<img>が返す Cache‑Control ヘッダーを活用し、max-age=86400(24h)でキャッシュ。- サーバー側が
ETagを付与している場合は、次回リクエスト時にIf-None-Matchを送ることで 304 Not Modified を取得できる。
Python(requests)サンプル
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import os, time, requests API_KEY = os.getenv('PEXELS_API_KEY') HEADERS = {'Authorization': f'Bearer {API_KEY}'} BASE_URL = 'https://api.pexels.com/v1/search' def search_photos(query: str, page: int = 1): params = { 'query': query, 'per_page': 15, 'page': page } resp = requests.get(BASE_URL, headers=HEADERS, params=params) if resp.status_code == 429: # Retry-After が無い場合はデフォルトで60秒待機 wait = int(resp.headers.get('Retry-After', 60)) print(f'Rate limit exceeded. Waiting {wait}s...') time.sleep(wait) return search_photos(query, page) resp.raise_for_status() return resp.json() if __name__ == '__main__': data = search_photos('秋 紅葉') for photo in data['photos'][:5]: print(photo['src']['medium']) |
Node.js(axios)サンプル
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
require('dotenv').config(); const axios = require('axios'); const apiKey = process.env.PEXELS_API_KEY; const client = axios.create({ baseURL: 'https://api.pexels.com/v1', headers: { Authorization: `Bearer ${apiKey}` } }); async function searchPhotos(query, page = 1) { try { const res = await client.get('/search', { params: { query, per_page: 12, page } }); return res.data.photos; } catch (err) { if (err.response?.status === 429) { const wait = parseInt(err.response.headers['retry-after'] || '60', 10); console.warn(`Rate limit hit. Waiting ${wait}s...`); await new Promise(r => setTimeout(r, wait * 1000)); return searchPhotos(query, page); // 再試行 } throw err; } } searchPhotos('海岸').then(photos => { photos.forEach(p => console.log(p.src.medium)); }); |
WordPress 用ショートコード実装
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<?php /** * Pexels 写真検索ショートコード [pexels_search query="花" per_page=9] */ function pexels_shortcode_photos( $atts ) { $args = shortcode_atts( array( 'query' => '', 'per_page' => 9, ), $atts ); if ( empty( $args['query'] ) ) return ''; // 定数または wp-config.php に定義した API キーを使用 $api_key = defined('PEXELS_API_KEY') ? PEXELS_API_KEY : ''; if ( ! $api_key ) return ''; $url = add_query_arg( array( 'query' => urlencode( $args['query'] ), 'per_page' => intval( $args['per_page'] ) ), 'https://api.pexels.com/v1/search' ); $response = wp_remote_get( $url, array( 'headers' => array( 'Authorization' => "Bearer {$api_key}" ) ) ); if ( is_wp_error( $response ) ) return ''; $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( empty( $data['photos'] ) ) return ''; $html = '<div class="pexels-gallery">'; foreach ( $data['photos'] as $photo ) { $src = esc_url( $photo['src']['medium'] ); $link = esc_url( $photo['url'] ); $alt = esc_attr( $photo['photographer'] ); $html .= "<a href='{$link}' target='_blank' rel='noopener'> <img src='{$src}' alt='{$alt}'> </a>"; } $html .= '</div>'; return $html; } add_shortcode( 'pexels_search', 'pexels_shortcode_photos' ); |
.htaccess でのキャッシュ設定例
|
1 2 3 4 5 |
<IfModule mod_headers.c> Header set Cache-Control "public, max-age=86400" FileETag MTime Size </IfModule> |
上記をサーバーに適用すれば、画像ファイルは 24 時間 キャッシュされ、同一リクエストの回数が削減できます。
ロゴ使用ガイドラインと商用利用時の注意点
Pexels のロゴや素材を自社サービスで利用する際に守るべきルールです。公式ドキュメント(https://www.pexels.com/ja-jp/api/)に基づいて解説します。
ロゴ表示ルール
- 使用できるバージョン:白版または黒版ロゴのみが許可されている。カラー版や加工したロゴは不可。
- 配置場所:サイトのヘッダー・フッターなど、明示的に Pexels へのクレジットを示す領域に限定。アプリのアイコンやブランドロゴとして使用することは禁止。
クレジット・画像改変ベストプラクティス
| 項目 | 推奨方法 |
|---|---|
| クレジット表記 | Photo by {photographer} on Pexels を画像近くに配置(必須ではないが推奨)。 |
| サイズ変更・トリミング | 許可されている。元画像の解像度やアスペクト比を変えても問題なし。 |
| 内容改変 | 人物の顔を合成したり、コンテキストを大幅に変える加工は避ける。 |
| 再販・二次配布 | ストックフォトサイトへのアップロードや有料販売は禁則事項。 |
利用規約の要点まとめ
| 項目 | 内容 |
|---|---|
| API キーの共有禁止 | プロジェクト単位で管理し、第三者に公開しない。 |
| レートリミット超過対策 | 1 時間あたり 200 リクエスト上限(公式)。バックオフとキャッシュ必須。 |
| ロゴの不適切使用 | アプリアイコン・ブランドロゴに利用不可。ヘッダー・フッター限定。 |
| 画像の再販禁止 | Pexels 素材を有料で販売、またはストックフォトとして再配布しない。 |
| 不適切コンテンツへの使用制限 | ポルノ、暴力的表現、差別的内容への利用は規約違反。 |
まとめと次のステップ
- API キー取得:公式ページから即時取得し、環境変数で安全管理。
- 認証:
Authorization: Bearer <キー>ヘッダーを必ず付与。 - エンドポイント:写真は
/v1/search、動画は/videos/searchを利用し、パラメータを正しく設定。 - レートリミット:公式情報(2024 年 10 月)に基づき、1 時間あたり 200 リクエストが上限。キャッシュ・バックオフで対策。
- レスポンス解析:
id,photographer,src等を活用し、必要なサイズの URL を取得。 - エラーハンドリング:401/403/429 の原因と再試行ロジックを実装。
- 実装例:JavaScript、Python、Node.js、WordPress 各言語でサンプルコードを提供。
- ロゴ・クレジット:公式ガイドラインに沿った表示方法と商用利用時の注意点を遵守。
これらの手順とベストプラクティスを踏めば、Pexels API を安全かつ効率的に自社サービスやブログへ組み込むことができます。ぜひ本稿をリファレンスとして活用し、高品質な画像・動画体験をユーザーに提供してください。
参考リンク
- 公式 API ドキュメント:https://www.pexels.com/ja-jp/api/
- レートリミットの最新情報(2024 年 10 月更新):同上ページ「Rate Limits」セクション
- ロゴ使用ガイドライン:公式ドキュメント内「Brand Assets」項目
※ 本稿は執筆時点(2026 年 6 月)における最新情報をもとに作成していますが、Pexels の仕様変更があった場合は公式サイトをご確認ください。