# Analytics và quảng cáo — VENO SDK 1.1.0

Admin: `/admin/studio?section=analytics` và `/admin/studio?section=ads`.
Chọn **game** để nhập GA4 Measurement ID hoặc chọn nhà cung cấp quảng cáo. Chọn **target** khi bản web và bản đưa lên cổng game dùng cấu hình khác nhau. Thứ tự kế thừa: mặc định → game → target; cấu hình target đóng gói trong game có ưu tiên cuối cùng.

Các game hiện vẫn tắt Analytics và quảng cáo. Bản cập nhật không thêm ID giả hoặc tự bật dịch vụ. Nút **Lưu nháp** chỉ lưu công việc; **Kiểm tra & xem thay đổi** hiển thị JSON trước/sau. Nhập `PUBLISH` để xuất bản, hoặc hẹn giờ UTC. Có lịch sử và khôi phục tại Remote config.

## Google Analytics theo game

1. Tạo GA4 property / Web data stream cho từng game, hoặc dùng chung một stream và phân tích theo `game_id`. Lấy **Measurement ID** dạng `G-...`, không dùng Measurement Protocol API secret.
2. Trong Analytics chọn `Game: ...`, chọn cấu hình riêng, điền ID, bật Analytics và đặt sample rate `1`. Với cấu hình cũ có sample rate `0`, cần tăng lên để bắt đầu đo lường.
3. Cấu hình CMP rồi chuyển trạng thái đồng ý vào `veno.consent.set(...)`. Không có đồng ý thì Google tag không được tải.
4. Tạm bật DebugView, xuất bản, mở game và kiểm tra `veno.analytics.getStatus()`. Sau khi cấp consent và chơi, kiểm tra Realtime / DebugView trong Google Analytics. Tắt DebugView khi kiểm tra xong.

SDK đặt `send_to` trên từng event để tránh gửi nhầm sang GA4 của game khác. Lấy mẫu một lần mỗi phiên khởi động, độc lập RNG gameplay. Các thông số chung gồm `game_id`, `game_version`, `sdk_version`, `target`, `lang`, `aspect`, `config_rev`. Đăng ký custom dimensions tương ứng trong GA4 nếu muốn dùng trong báo cáo.

Các event gameplay sẵn có: `game_start`, `level_complete`, `level_fail`; quảng cáo: `ad_request`, `ad_started`, `ad_result`, `ad_shown`, `reward_granted`; SDK: `veno_session_start`, `veno_session_end`, `sdk_boot`, `game_ready`. Sự kiện trước consent không được lưu/gửi bù. `sdk_boot` và `game_ready` chỉ xuất hiện nếu consent được cấp trước thời điểm tương ứng.

```js
veno.track('g_hint_used', { level: 4, source: 'rewarded' });
veno.analytics.flush();
console.table(veno.analytics.getStatus().recent); // Chỉ lưu 20 event gần nhất khi debug bật
```

Tối đa 10 tên sự kiện `g_*` mỗi phiên, 12 tham số tùy chỉnh mỗi event, chuỗi tối đa 100 ký tự. SDK lọc một số khóa nhạy cảm thông dụng nhưng game vẫn phải tránh gửi tên, email, ID người dùng, dữ liệu nhập tự do hoặc URL chứa bí mật. SDK không gửi query/hash của URL trong cấu hình Google tag. Tắt các Enhanced Measurement không cần thiết trong GA4; những tính năng tự động của Google tag hoặc script bên ngoài không do hàng đợi VENO quản lý.

`getStatus().state`: `disabled`, `missing_measurement_id`, `consent_required`, `sampled_out`, `demo`, `loading`, `ready`, `error`, `inactive`. `ready` xác nhận Google tag tải xong; phải kiểm tra GA4 để xác nhận máy chủ đã nhận dữ liệu. Admin hiển thị trạng thái cấu hình, chưa kết nối GA4 Data API để đọc số liệu thống kê.

## Nền tảng quảng cáo

| Provider | Interstitial | Rewarded | Cấu hình / phạm vi |
|---|---|---|---|
| `adsense-h5` | Có | Có | Publisher ID `ca-pub-...`, tài khoản H5 được Google chấp thuận; có test mode |
| `crazygames` | Có | Có | CrazyGames SDK v3, game được tiếp nhận trên CrazyGames |
| `poki` | Có | Có | Poki SDK v2, game được tiếp nhận trên Poki |
| `gamedistribution` | Có | Có | Game ID trong GameDistribution |
| `gamemonetize` | Có | Không | Game ID trong GameMonetize; rewarded trả `no_fill` |
| `mock` | Mô phỏng | Mô phỏng | Chỉ dùng nội bộ, không có doanh thu |
| `admob-bridge` | Qua native | Qua native | Cần tự cung cấp Capacitor `VenoAds` plugin; không phải quảng cáo web |

Mỗi game/target dùng một provider. Không có waterfall tự động giữa các cổng game. Không có banner display trong bản này. CrazyGames, Poki, GameDistribution và GameMonetize là các môi trường phân phối; không phải nhà cung cấp có thể bật tùy ý để kiếm tiền ngay trên website riêng. Hoàn tất xét duyệt và kiểm thử của nền tảng trước khi phát hành. GameMonetize yêu cầu liên hệ họ nếu muốn self-host.

```js
// Gắn vào nút/chuyển cảnh tự nhiên, sau hành động người chơi.
await veno.ads.interstitial('level_end');

// Nút phải ghi rõ xem quảng cáo để nhận thưởng.
if (veno.ads.isRewardedReady('hint')) {
  const result = await veno.ads.rewarded('hint');
  if (result.granted) giveHint();
}
console.log(veno.ads.getStatus());
```

Placement phải có trong manifest. Admin cho bật/tắt từng placement, khoảng miễn quảng cáo đầu phiên, khoảng cách interstitial, giới hạn theo phiên và khoảng nghỉ sau rewarded. SDK tạm dừng game, tắt tiếng trong lúc chờ/phát quảng cáo và khôi phục khi kết thúc. Thời gian chờ bắt đầu mặc định 8 giây; khi nhận `adStarted` chuyển sang giới hạn 180 giây. Có thể điều chỉnh trong Admin. Nếu provider không trả lời trước giới hạn, game được khôi phục, thưởng bị từ chối và provider bị khóa đến khi tải lại trang để tránh chồng quảng cáo hoặc nhận nhầm callback muộn.

Rewarded chỉ cấp thưởng khi provider xác nhận: Google `adViewed`, CrazyGames `adFinished`, Poki kết quả `true`, GameDistribution `SDK_REWARDED_WATCH_COMPLETE`. Không cấp thưởng chỉ vì lệnh gọi API thành công. Không gửi quảng cáo khi demo, clean, quay video, offline, chưa consent hoặc đã mua no-ads. `isRewardedReady()` chỉ cho biết adapter sẵn sàng nhận yêu cầu, không cam kết sẽ có quảng cáo.

## Consent

```js
// Trong callback CMP, sau khi đã xác minh consent theo purpose VÀ vendor:
veno.consent.set({
  analytics: analyticsAllowed,
  ads: selectedAdVendorAllowed,
  personalized: personalizationAllowed
});
// Thu hồi quyền:
veno.consent.set({ analytics: false, ads: false, personalized: false });
```

VENO không tự suy diễn đồng ý cho tất cả vendor từ một TCF purpose bit. CMP tích hợp cần thực hiện ánh xạ phù hợp, truyền tín hiệu mà provider yêu cầu và cập nhật mỗi khi người dùng đổi lựa chọn. Google nhận Consent Mode; AdSense yêu cầu non-personalized khi personalization bị từ chối. Các portal SDK xử lý CMP của họ; callback VENO là lớp chặn bổ sung, không thay thế CMP của nền tảng. Sau khi rút consent, VENO ngừng gửi event/yêu cầu quảng cáo mới; script của provider đã tải vẫn tồn tại và CMP cần cập nhật trực tiếp tín hiệu của provider. Game dành cho trẻ em luôn vô hiệu hóa cờ personalization của VENO.

Không có CMP hay ID thì giữ dịch vụ tắt. Không nhập API secrets vào JSON public. Thay provider, tài khoản hoặc test mode cần tải lại trang.

## Kiểm thử và tài liệu chính thức

Kiểm thử tự động sử dụng SDK giả lập để kiểm tra callback, consent, route GA4, timeout và thưởng. Chưa kiểm chứng doanh thu hoặc ad fill thực tế do chưa có tài khoản được duyệt.

- [Google tag routing](https://developers.google.com/tag-platform/gtagjs/routing)
- [Google Consent Mode](https://developers.google.com/tag-platform/security/guides/consent)
- [AdSense H5 Ad Placement API](https://developers.google.com/ad-placement/apis)
- [CrazyGames video ads](https://docs.crazygames.com/sdk/video-ads/)
- [Poki HTML5 SDK](https://developers.poki.com/guide/sdk-html5)
- [GameDistribution SDK](https://github.com/GameDistribution/GD-HTML5/wiki/SDK-Implementation)
- [GameMonetize SDK](https://github.com/MonetizeGame/GameMonetize.com-SDK)
