พร็อกซีความเป็นส่วนตัวของเบราว์เซอร์และการตั้งค่าการปกป้อง IP สามารถปิดบังที่อยู่ IP ของไคลเอ็นต์ในคำขอโฆษณาของบุคคลที่สามที่ส่งไปยัง Google Ad Manager ได้ ที่อยู่ IP ที่มาสก์อาจลดความแม่นยำในการกำหนดเป้าหมายตามภูมิศาสตร์และความเกี่ยวข้องของโฆษณา เนื่องจากเว็บเซิร์ฟเวอร์หรือเครือข่ายนำส่งข้อมูล (CDN) โต้ตอบกับผู้ใช้ในบริบทของบุคคลที่หนึ่ง เซิร์ฟเวอร์จึงได้รับที่อยู่ IP ที่ไม่ปกปิดของผู้ใช้
ฟีเจอร์ IP ที่ผู้เผยแพร่โฆษณาจัดหาให้ช่วยให้คุณบันทึกที่อยู่ IPv4 หรือ IPv6 ที่ไม่มาสก์ของผู้ใช้ในเซิร์ฟเวอร์ เข้ารหัสที่อยู่โดยใช้ Hybrid Public Key Encryption (HPKE) และส่งเพย์โหลดที่เข้ารหัสไปยังแท็กผู้เผยแพร่โฆษณาผ่าน Google (GPT) ในไคลเอ็นต์
หน้านี้ครอบคลุมการผสานรวม IP ที่ผู้เผยแพร่โฆษณาจัดหาให้เข้ากับ GPT
ใช้เวิร์กโฟลว์ฝั่งเซิร์ฟเวอร์
หากต้องการหลีกเลี่ยงการเปิดเผยที่อยู่ IP แบบข้อความธรรมดาของผู้ใช้ต่อสคริปต์ของบุคคลที่สามในเบราว์เซอร์ ให้ทำตามขั้นตอนต่อไปนี้ในเว็บเซิร์ฟเวอร์หรือ Edge Worker ของ CDN
- จับภาพ IP ทั้งหมด
- ดึงข้อมูลคีย์สาธารณะ
- ทำการเข้ารหัส HPKE
บันทึกที่อยู่ IP ของไคลเอ็นต์
ดึงข้อมูลที่อยู่ IPv4 หรือ IPv6 ที่ไม่ปกปิดของไคลเอ็นต์จากคำขอหน้าเว็บขาเข้าบนเว็บเซิร์ฟเวอร์หรือ CDN โดยทำดังนี้
- การเชื่อมต่อโดยตรง: อ่านที่อยู่ซ็อกเก็ตระยะไกลของการเชื่อมต่อ HTTP ขาเข้า
- อยู่หลัง CDN, ตัวจัดสรรภาระงาน หรือพร็อกซีแบบย้อนกลับ: อ่านส่วนหัว IP ของไคลเอ็นต์จากพร็อกซี Edge ที่เชื่อถือได้ เช่น ส่วนหัว
X-Forwarded-Forหรือส่วนหัว IP ของไคลเอ็นต์เฉพาะ CDN เชื่อถือเฉพาะส่วนหัวการส่งต่อที่โครงสร้างพื้นฐานพร็อกซีของคุณเพิ่มหรือลบล้างเท่านั้น เมื่อส่วนหัวX-Forwarded-Forมีที่อยู่หลายรายการที่คั่นด้วยคอมมา ให้เลือก IP ของไคลเอ็นต์ที่พร็อกซี Edge ที่เชื่อถือได้เพิ่ม
Ad Manager รองรับที่อยู่ต่อไปนี้
- IPv4 เช่น
203.0.113.42 - IPv6 เช่น
2001:db8::8a2e:370:7334
ส่งเฉพาะสตริงที่อยู่ IP เปล่า โดยไม่มีหมายเลขพอร์ต วงเล็บ คำนำหน้า CIDR หรือช่องว่างโดยรอบ
ดึงข้อมูลและแคชคีย์สาธารณะ
Google เผยแพร่คีย์การเข้ารหัส HPKE ที่ใช้งานอยู่เป็น RFC 8037 JSON Web Key Set (JWKS) ที่ปลายทางต่อไปนี้
https://www.gstatic.com/real-ip/ip_enc_key.json
คำขอ GET ไปยังปลายทางนี้จะแสดงผลออบเจ็กต์ JSON ซึ่งอาร์เรย์ keys มีออบเจ็กต์คีย์ที่ใช้งานอยู่รายการเดียว ใช้คีย์ในพร็อพเพอร์ตี้ x ของออบเจ็กต์นั้นเพื่อเข้ารหัสที่อยู่ IP ของไคลเอ็นต์
ตัวอย่างต่อไปนี้จะดึงข้อมูลคีย์สาธารณะและดึงข้อมูลพร็อพเพอร์ตี้ x เมื่อดำเนินการสำเร็จ และแสดงข้อยกเว้นเมื่อดำเนินการไม่สำเร็จ
Java
private static final String KEY_ENDPOINT_URL = "https://www.gstatic.com/real-ip/ip_enc_key.json";
/**
* Fetches the active X25519 public key from Google's key endpoint.
*
* <p>In production, cache the returned public key in memory and refresh it at least once every 24
* hours rather than fetching it on every incoming request.
*
* @return The unpadded Base64URL-encoded 32-byte X25519 public key ('x').
*/
public static String fetchPublicKey() throws IOException, InterruptedException {
return fetchPublicKey(KEY_ENDPOINT_URL);
}
public static String fetchPublicKey(String endpointUrl) throws IOException, InterruptedException {
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();
HttpRequest request =
HttpRequest.newBuilder()
.uri(URI.create(endpointUrl))
.timeout(Duration.ofSeconds(5))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IOException("Failed to fetch public key, HTTP status: " + response.statusCode());
}
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
JsonArray keys = json.getAsJsonArray("keys");
if (keys == null || keys.isEmpty()) {
throw new IOException("No keys found in response from " + endpointUrl);
}
JsonObject keyObj = keys.get(0).getAsJsonObject();
if (!keyObj.has("x")) {
throw new IOException("Key payload missing 'x' property: " + keyObj);
}
return keyObj.get("x").getAsString();
}
Python
KEY_ENDPOINT_URL = "https://www.gstatic.com/real-ip/ip_enc_key.json"
def fetch_public_key(url: str = KEY_ENDPOINT_URL) -> str:
"""Fetches the active X25519 public key from Google's key endpoint.
In production, cache the returned public key in memory and refresh it at
least once every 24 hours rather than fetching it on every incoming request.
Args:
url: URL of the public key endpoint.
Returns:
The unpadded Base64URL-encoded 32-byte X25519 public key ('x').
"""
with urllib.request.urlopen(url, timeout=5) as response:
data = json.loads(response.read().decode("utf-8"))
keys = data.get("keys", [])
if not keys:
raise ValueError(f"No keys found in response from {url}")
key_payload = keys[0].get("x")
if not key_payload:
raise ValueError(f"Key payload missing 'x' property: {keys[0]}")
return key_payload
JavaScript
const KEY_ENDPOINT_URL = 'https://www.gstatic.com/real-ip/ip_enc_key.json';
/**
* Fetches the active X25519 public key from Google's key endpoint.
*
* In production, cache the returned public key in memory and refresh it at
* least once every 24 hours rather than fetching it on every incoming request.
*
* @param {string=} url URL of the public key endpoint.
* @return {!Promise<string>} The unpadded Base64URL-encoded 32-byte X25519
* public key ('x').
*/
async function fetchPublicKey(url = KEY_ENDPOINT_URL) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to fetch public key, HTTP status: ${response.status}`,
);
}
const data = await response.json();
if (!data.keys || data.keys.length === 0) {
throw new Error(`No keys found in response from ${url}`);
}
const keyPayload = data.keys[0].x;
if (!keyPayload) {
throw new Error(
`Key payload missing 'x' property: ${JSON.stringify(data.keys[0])}`,
);
}
return keyPayload;
}
TypeScript
const KEY_ENDPOINT_URL = 'https://www.gstatic.com/real-ip/ip_enc_key.json';
interface JwkKey {
kty?: string;
crv?: string;
x?: string;
kid?: string;
}
interface KeyEndpointResponse {
keys?: JwkKey[];
}
/**
* Fetches the active X25519 public key from Google's key endpoint.
*
* In production, cache the returned public key in memory and refresh it at
* least once every 24 hours rather than fetching it on every incoming request.
*
* @param url URL of the public key endpoint.
* @return The unpadded Base64URL-encoded 32-byte X25519 public key ('x').
*/
export async function fetchPublicKey(
url: string = KEY_ENDPOINT_URL,
): Promise<string> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to fetch public key, HTTP status: ${response.status}`,
);
}
const data = (await response.json()) as KeyEndpointResponse;
if (!data.keys || data.keys.length === 0) {
throw new Error(`No keys found in response from ${url}`);
}
const keyPayload = data.keys[0].x;
if (!keyPayload) {
throw new Error(
`Key payload missing 'x' property: ${JSON.stringify(data.keys[0])}`,
);
}
return keyPayload;
}
หากทำสำเร็จ การตอบกลับจะมีอาร์เรย์ keys ที่มีออบเจ็กต์คีย์พร้อมพร็อพเพอร์ตี้ x ดังนี้
{
"keys": [
{
"kty": "OKP",
"crv": "X25519",
"x": "7bws5TIHOUrcJNofEubW3DPW8zR9EtjFNLm_Grv98TA",
"kid": "EZMLFw"
}
]
}
ตารางต่อไปนี้อธิบายพร็อพเพอร์ตี้ของออบเจ็กต์คีย์ในอาร์เรย์ keys
| พร็อพเพอร์ตี้ | คำอธิบาย |
|---|---|
crv |
ตัวระบุเส้นโค้งวงรี X25519 เสมอ |
kid |
ตัวระบุคีย์ที่เข้ารหัส base64url แบบไม่มีการเติม ซึ่งจะเปลี่ยนเมื่อ Google หมุนเวียนคีย์ |
kty |
ประเภทคีย์ OKP (คู่คีย์อ็อกเท็ต) เสมอ |
x |
คีย์สาธารณะ X25519 แบบข้อมูลดิบขนาด 32 ไบต์ที่เข้ารหัส base64url แบบไม่มีอักขระแทรกซึ่งใช้สำหรับการเข้ารหัส |
แคชคีย์สาธารณะที่ดึงมาในหน่วยความจำบนเซิร์ฟเวอร์และรีเฟรชคีย์อย่างน้อย 1 ครั้งทุกๆ 24 ชั่วโมง หรือเร็วกว่านั้นตามส่วนหัวการตอบกลับ HTTP Cache-Control อย่าดึงข้อมูลคีย์สาธารณะในคำขอหน้าเว็บขาเข้าทุกรายการ
Google จะเก็บคีย์ส่วนตัวที่หมุนเวียนไว้ เพย์โหลดที่เข้ารหัสด้วยคีย์สาธารณะที่แคชไว้ในช่วง 24 ชั่วโมงก่อนหน้าจะยังคงถอดรหัสต่อไปโดยไม่หยุดชะงักในระหว่างการหมุนเวียนคีย์
เข้ารหัสที่อยู่ IP
เข้ารหัสการแสดงผลไบต์ UTF-8 ของสตริงที่อยู่ IP ของไคลเอ็นต์โดยใช้ HPKE (RFC 9180) และคีย์สาธารณะ X25519 ขนาด 32 ไบต์ที่ถอดรหัสแล้ว x ซึ่งดึงมาในดึงข้อมูลและแคชคีย์สาธารณะ
ตัวอย่างต่อไปนี้จะเข้ารหัสสตริงที่อยู่ IP
Java
ตัวอย่างนี้ใช้ Tink (com.google.crypto.tink:tink 1.16.0 ขึ้นไป) ดังนี้
static {
try {
HybridConfig.register();
} catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
/**
* Encrypts an IP address using HPKE (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-256-GCM).
*
* @param pubXB64Url Base64URL-encoded 32-byte X25519 public key ('x').
* @param ipStr Plaintext IPv4 or IPv6 address string (for example, "203.0.113.42").
* @return Unpadded Base64URL-encoded payload (enc || ciphertext).
*/
@AccessesPartialKey
public static String encryptIp(String pubXB64Url, String ipStr) throws GeneralSecurityException {
// 1. Decode the 32-byte X25519 public key 'x' from Base64URL.
byte[] pubBytes = Base64.getUrlDecoder().decode(pubXB64Url);
if (pubBytes.length != 32) {
throw new IllegalArgumentException(
"Public key must be exactly 32 bytes, got " + pubBytes.length);
}
// 2. Configure HPKE parameters (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
// AES_256_GCM, NO_PREFIX).
HpkeParameters parameters =
HpkeParameters.builder()
.setKemId(HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256)
.setKdfId(HpkeParameters.KdfId.HKDF_SHA256)
.setAeadId(HpkeParameters.AeadId.AES_256_GCM)
.setVariant(HpkeParameters.Variant.NO_PREFIX)
.build();
HpkePublicKey publicKey =
HpkePublicKey.create(parameters, Bytes.copyFrom(pubBytes), /* idRequirement= */ null);
// 3. Encrypt the UTF-8 IP address bytes. With Variant.NO_PREFIX, Tink
// outputs raw (enc || ciphertext_with_tag).
KeysetHandle handle =
KeysetHandle.newBuilder()
.addEntry(KeysetHandle.importKey(publicKey).withRandomId().makePrimary())
.build();
HybridEncrypt encryptor = handle.getPrimitive(RegistryConfiguration.get(), HybridEncrypt.class);
byte[] payload =
encryptor.encrypt(ipStr.getBytes(StandardCharsets.UTF_8), /* contextInfo= */ new byte[0]);
// 4. Return unpadded Base64URL-encoded payload.
return Base64.getUrlEncoder().withoutPadding().encodeToString(payload);
}
Python
ตัวอย่างนี้ใช้ pyhpke:
def encrypt_ip(pub_x_b64url: str, ip_str: str) -> str:
"""Encrypts an IP address using HPKE (RFC 9180).
Args:
pub_x_b64url: Base64URL-encoded 32-byte X25519 public key ('x').
ip_str: Plaintext IPv4 or IPv6 address string (for example, "203.0.113.42").
Returns:
Unpadded Base64URL-encoded payload (enc || ciphertext).
"""
# 1. Decode the 32-byte X25519 public key 'x' from Base64URL.
pub_bytes = base64.urlsafe_b64decode(
pub_x_b64url + "=" * (-len(pub_x_b64url) % 4)
)
if len(pub_bytes) != 32:
raise ValueError(
f"Public key must be exactly 32 bytes, got {len(pub_bytes)}"
)
# 2. Configure HPKE cipher suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
# AES256_GCM).
suite = CipherSuite.new(
KEMId.DHKEM_X25519_HKDF_SHA256, KDFId.HKDF_SHA256, AEADId.AES256_GCM
)
public_key = suite.kem.deserialize_public_key(pub_bytes)
# 3. Create a fresh sender context per encryption (you may cache 'suite' and
# 'public_key', but never reuse 'sender' across multiple seal() calls) and
# package (enc || ciphertext).
enc, sender = suite.create_sender_context(public_key)
ciphertext = sender.seal(ip_str.encode("utf-8"))
# 4. Return unpadded Base64URL-encoded payload.
return base64.urlsafe_b64encode(enc + ciphertext).decode("utf-8").rstrip("=")
JavaScript
ตัวอย่างนี้ใช้ @hpke/core:
/**
* Encrypts an IP address using HPKE (RFC 9180).
*
* @param {string} pubXB64Url Base64URL-encoded 32-byte X25519 public key ('x').
* @param {string} ipStr Plaintext IPv4 or IPv6 address string (for example,
* "203.0.113.42").
* @return {!Promise<string>} Unpadded Base64URL-encoded payload
* (enc || ciphertext).
*/
async function encryptIp(pubXB64Url, ipStr) {
// 1. Decode the 32-byte X25519 public key 'x' from Base64URL.
const pubBytes = Buffer.from(pubXB64Url, 'base64url');
if (pubBytes.length !== 32) {
throw new Error(
`Public key must be exactly 32 bytes, got ${pubBytes.length}`,
);
}
// 2. Configure HPKE cipher suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
// AES_256_GCM).
const suite = new CipherSuite({
kem: new DhkemX25519HkdfSha256(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
const rawPubKey = new Uint8Array(pubBytes).buffer;
const publicKey = await suite.kem.importKey('raw', rawPubKey, true);
// 3. Encrypt the UTF-8 IP address bytes and package (enc || ciphertext).
const plaintext = new Uint8Array(Buffer.from(ipStr, 'utf8')).buffer;
const {enc, ct} = await suite.seal(
{recipientPublicKey: publicKey},
plaintext,
);
// 4. Return unpadded Base64URL-encoded payload.
return Buffer.concat([Buffer.from(enc), Buffer.from(ct)]).toString(
'base64url',
);
}
TypeScript
ตัวอย่างนี้ใช้ @hpke/core:
/**
* Encrypts an IP address using HPKE (RFC 9180).
*
* @param pubXB64Url Base64URL-encoded 32-byte X25519 public key ('x').
* @param ipStr Plaintext IPv4 or IPv6 address string (for example,
* "203.0.113.42").
* @return Unpadded Base64URL-encoded payload (enc || ciphertext).
*/
export async function encryptIp(
pubXB64Url: string,
ipStr: string,
): Promise<string> {
// 1. Decode the 32-byte X25519 public key 'x' from Base64URL.
const pubBytes = Buffer.from(pubXB64Url, 'base64url');
if (pubBytes.length !== 32) {
throw new Error(
`Public key must be exactly 32 bytes, got ${pubBytes.length}`,
);
}
// 2. Configure HPKE cipher suite (DHKEM_X25519_HKDF_SHA256, HKDF_SHA256,
// AES_256_GCM).
const suite = new CipherSuite({
kem: new DhkemX25519HkdfSha256(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});
const rawPubKey = new Uint8Array(pubBytes).buffer;
const publicKey = await suite.kem.importKey('raw', rawPubKey, true);
// 3. Encrypt the UTF-8 IP address bytes and package (enc || ciphertext).
const plaintext = new Uint8Array(Buffer.from(ipStr, 'utf8')).buffer;
const {enc, ct} = await suite.seal(
{recipientPublicKey: publicKey},
plaintext,
);
// 4. Return unpadded Base64URL-encoded payload.
return Buffer.concat([Buffer.from(enc), Buffer.from(ct)]).toString(
'base64url',
);
}
กำหนดค่าไลบรารี HPKE ด้วยชุดการเข้ารหัสและพารามิเตอร์ต่อไปนี้
| พารามิเตอร์ | ค่า |
|---|---|
| กลไกการห่อหุ้มข้อมูลคีย์ (KEM) | DHKEM(X25519, HKDF-SHA256) (0x0020) |
| ฟังก์ชันการรับคีย์ (KDF) | HKDF-SHA256 (0x0001) |
| การเข้ารหัสที่ตรวจสอบสิทธิ์แล้วพร้อมข้อมูลที่เกี่ยวข้อง (AEAD) | AES-256-GCM (0x0002) |
| โหมด | ฐาน (0x00) |
ข้อมูลแอปพลิเคชัน (info) |
ว่าง ("") |
ข้อมูลที่เชื่อมโยง (aad) |
ว่าง ("") |
จัดรูปแบบเอาต์พุตที่เข้ารหัสเป็นการเชื่อมโยงดิบของคีย์สาธารณะชั่วคราวที่แคปซูลขนาด 32 ไบต์ enc และข้อความเข้ารหัส AEAD รวมถึงแท็กการตรวจสอบสิทธิ์ GCM ขนาด 16 ไบต์ โดยไม่มี Tink หรือคำนำหน้าส่วนหัวที่กำหนดเอง เข้ารหัสผลลัพธ์เป็นสตริง base64url ที่ไม่มีการเติมอักขระ
เข้ารหัสเพย์โหลดแต่ละรายการเป็นข้อความ HPKE แบบครั้งเดียวสแตนด์อโลนด้วยคู่คีย์ชั่วคราวใหม่ หากไลบรารี HPKE ใช้บริบทผู้ส่งแบบเก็บสถานะ ให้สร้างบริบทใหม่สำหรับการเข้ารหัสแต่ละครั้งแทนที่จะใช้ซ้ำในข้อความหลายรายการ เข้ารหัสที่อยู่ IP ของไคลเอ็นต์ต่อคำขอหน้าเว็บ หรือแคชสตริงข้อความเข้ารหัส base64url ที่ได้ต่อที่อยู่ IP เป็นระยะเวลาสั้นๆ (TTL)
ใช้เวิร์กโฟลว์ฝั่งไคลเอ็นต์
หลังจากเซิร์ฟเวอร์สร้างเพย์โหลด IP base64url ที่เข้ารหัสแล้ว ให้ส่งเพย์โหลดไปยัง GPT ในไคลเอ็นต์ก่อนขอโฆษณา
ส่ง IP ที่เข้ารหัสไปยัง GPT
ส่งสตริง IP ที่เข้ารหัสไปยังเมธอด googletag.setConfig โดยใช้พร็อพเพอร์ตี้ ipAddress ใน PageSettingsConfig
ตัวอย่างต่อไปนี้จะแทรกเพย์โหลด IP ที่เข้ารหัสซึ่งเซิร์ฟเวอร์สร้างขึ้นลงในเมธอด googletag.setConfig ก่อนเปิดใช้บริการและแสดงช่องโฆษณา
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Publisher-provided IP example</title>
<script src="https://securepubads.g.doubleclick.net/tag/js/gpt.js" crossorigin="anonymous" async></script>
<script>
window.googletag = window.googletag || {cmd: []};
// Inject the base64url-encoded encrypted IP generated by your server.
const encryptedClientIp = 'ENCRYPTED_IP_PAYLOAD';
googletag.cmd.push(function() {
// Configure the encrypted IP before enabling services.
googletag.setConfig({
ipAddress: encryptedClientIp,
});
googletag
.defineSlot('/6355419/Travel/Europe/France/Paris', [300, 250], 'banner-ad')
.addService(googletag.pubads());
googletag.enableServices();
});
</script>
</head>
<body>
<div id="banner-ad" style="width: 300px; height: 250px;"></div>
<script>
googletag.cmd.push(function() {
googletag.display('banner-ad');
});
</script>
</body>
</html>แทนที่ ENCRYPTED_IP_PAYLOAD ด้วยสตริงที่เข้ารหัส base64url แบบไม่มีการเติมที่เซิร์ฟเวอร์สร้างขึ้น
หากต้องการล้างที่อยู่ IP ที่กำหนดค่าไว้ก่อนหน้านี้ในหน้าเว็บ ให้ตั้งค่าพร็อพเพอร์ตี้ ipAddress เป็นค่า null ดังนี้
googletag.setConfig({ ipAddress: null });
ยืนยันการผสานรวม
หากต้องการยืนยันว่า GPT ส่งเพย์โหลด IP ที่เข้ารหัสและ Ad Manager ถอดรหัสเพย์โหลด ให้ใช้เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์และคอนโซลผู้เผยแพร่โฆษณาของ Google โดยทำดังนี้
เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ในเบราว์เซอร์
- เปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์
- เลือกแท็บเครือข่าย
- กรองคำขอโฆษณาไปยัง
/gampad/ads - ตรวจสอบว่า URL คำขอมีพารามิเตอร์การค้นหา
ipsที่ไม่ว่างเปล่า เนื่องจาก GPT จะเข้ารหัสค่าipAddressเพิ่มเติมก่อนส่งคำขอโฆษณา พารามิเตอร์ipsจึงไม่ตรงกับสตริงที่เข้ารหัสของคุณทุกคำ
คอนโซลผู้เผยแพร่โฆษณาของ Google
- หากต้องการเปิดคอนโซล ให้ทำตามขั้นตอนในคู่มือคอนโซลผู้เผยแพร่โฆษณาของ Google
- เลือกแท็บคำขอหน้าเว็บ
ตรวจสอบว่าไม่มีคำเตือน
ipAddressปรากฏขึ้น หากมีปัญหาเกี่ยวกับเพย์โหลด คอนโซลจะบันทึกคำเตือนอย่างใดอย่างหนึ่งต่อไปนี้หากค่าที่ส่งไปยังพร็อพเพอร์ตี้
ipAddressไม่ใช่สตริง base64 หรือ base64url ที่ถูกต้องซึ่งมีความยาวระหว่าง 67 ถึง 124 อักขระ GPT จะละเว้นค่าดังกล่าว ละเว้นพารามิเตอร์ipsจากคำขอโฆษณา และบันทึกคำเตือนต่อไปนี้Invalid value encountered when calling: googletag.setConfig: {"ipAddress":"..."}. (string) ... was found at PageSettingsConfig.ipAddress. Invalid IP address format.หาก Ad Manager ไม่สามารถถอดรหัสเพย์โหลด IP ที่ระบุ หรือหากข้อความธรรมดาที่ถอดรหัสแล้วไม่ใช่ที่อยู่ IPv4 หรือ IPv6 ที่ถูกต้อง คอนโซลจะบันทึกคำเตือนต่อไปนี้และกลับไปใช้ที่อยู่ IP ของคำขอเครือข่าย
Decryption failed on the provided encrypted client IP (supplied via googletag.setConfig({ipAddress: ...})).