Is Google Translate Assistant – Side-by-side Translation | PDF Translation safe?
Google Translate Assistant sends page URLs, device identifiers, and tab screenshots to its vendor servers during normal use.
On every user action and daily check-in, the extension transmits a persistent device UUID, user ID, IP country code, and OS fingerprint to translate-useraction-api.xiangtatech.com. When auto-translate is checked for a page, the full URL of that page is sent to translate-api.xiangtatech.com to determine eligibility. If the user invokes the OCR translate feature, a screenshot of the visible tab is captured and uploaded to the same vendor server for processing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
OCR translation uploads selected page images
OCR translation captures the visible tab as a PNG for cropping.
After you confirm the crop, the image and language choices go into multipart form data posted to the picture-translation endpoint.
A runtime test did not trigger this path.
You start screenshot translation and confirm a cropped region of the current page.
The extension captures the visible tab, converts your selected crop into a PNG file, and sends it for picture translation.
| Field | Value | Why it matters | |
|---|---|---|---|
Selected page image | image.png from the selected crop | Sends the visible text and graphics inside the crop you confirm. | |
Source language | from auto | Tells the translation service which language the selected image starts from. | |
Target language | to en | Tells the translation service which language to translate into. | |
Page range markers | start_page -1, end_page -1 | Adds fixed page-range fields even though the upload is a screenshot image. |
The screenshot path captures the tab and uploads the cropped image
case "screenshot":
chrome.tabs.captureVisibleTab(t.tab.windowId, {
format: "png"
}, (e => n(e)));
break; enter() {
this.captureing || (this.captureing = !0, chrome.runtime.sendMessage({
type: "screenshot"
}, (e => {
this.bodyOverflow = document.documentElement.style.overflow, document.documentElement.style.overflow = "hidden", document.addEventListener("keydown", this.onKeydown_), this.imgURL = e, this.isShow = !0
})))
},
confirm() {
if (!this.cropper) return this.cancel();
const e = {
from: this.sourceItem.gid,
to: this.targetItem.gid
};
this.cropper.getCroppedCanvas().toBlob((t => {
this.cancel(), this.$emit("confirm", t, e)
}))
} ocr(e, t) {
var n, o;
if (this.loading) return void eo(this.$t("ocr.loading"), {
appendToEl: this.$refs.box
});
if (!e && !this.ocrBlob) return;
this.initOriginImg(e || this.ocrBlob), t && (t.from && (null == (n = this.$refs.switchLangRef) || n.setSourceLang(t.from)), t.to && (null == (o = this.$refs.switchLangRef) || o.setTargetLang(t.to))), this.showSceneCoupon = !1, e ? this.ocrBlob = e : e = this.ocrBlob;
const a = new FormData,
i = new File([e], "image.png", {
type: e.type
});
a.append("file", i), a.append("from", this.sourceItem.gid), a.append("to", this.targetItem.gid), a.append("start_page", -1), a.append("end_page", -1), ao({
url: "https://translate-api.xiangtatech.com/translate/translation/webs/picture",
type: "post",
formData: a,
dataType: "json",
success: e => {
var t, n;
e.data ? (this.clearTransData(), this.loading = !0, this.queryTaskTime(null == (t = e.data) ? void 0 : t.file_translation_id), this.isShow = !0, this.currentTaskId = null == (n = e.data) ? void 0 : n.file_translation_id) : (this.ocrError(e.msg || this.$t("ocr.noText")), this.showErrorDialog = !0)
},
error: e => {
var t, n;
1011 !== (null == (t = e.response) ? void 0 : t.code) ? 406 !== (null == (n = e.response) ? void 0 : n.code) ? (this.ocrError(e.response && (e.response.msg || e.response.message) || this.$t("ocr.fail"), e.response && e.response.code || e.status), this.showErrorDialog = !0) : eo(this.$t("ocr.notSupportedFile")) : eo(this.$t("ocr.loading"), {
appendToEl: this.$refs.box
})
}
})
}, startOcrTranslate(e) {
return c(this, null, (function*() {
if (yield this.closeOpenedFunDialog(), !this.canScreenshot) return;
this.inScreenshot = !0, setTimeout((() => {
this.$refs.screenshotTool.enter()
}), 24);
const t = {
param15: "default"
};
e && Object.assign(t, e), this.$mergeSubmitReport({
event_id: 107,
extend_fields: t
})
}))
},
onScreenshotConfirm(e, t) {
return c(this, null, (function*() {
var n;
this.inScreenshot = !1, null == (n = this.$refs.imageTranslate) || n.close((() => {
var n;
null == (n = this.$refs.ocrTranslate) || n.ocr(e, t)
}))
}))
},- translate-api.xiangtatech.com
Vendor picture-translation endpoint that receives the cropped screenshot image form.
Persistent browser identifiers sent in action reports
The extension posts a user-action report with a persistent browser-ID prefix, OS values, event IDs, and IP-country context to translate-api.kangaroooffice.com.
It reads stored account/device state, posts reports on install and daily checks.
You browse or use extension features while Google Translate Assistant is active.
The extension builds a user-action report with a persistent browser identifier, device details, event IDs, and account fields when available.
| Content-Type | application/json |
| Field | Value | Why it matters | |
|---|---|---|---|
Persistent browser identifier | pcid beginning fe13fa8a | Lets the reporting service connect separate reports from the same browser over time. | |
Account identifier when signed in | user_id 92837465 (illustrative) | Links the report to the extension account if account data is stored locally. | |
IP-country context | 美国 | Adds the country associated with your network location to the report. | |
Operating system details | os_type 1, os_version 41658296553177090 | Adds device context that helps distinguish browsers and environments. | |
Extension event IDs | event_id 1, 100, 101, or 243 | Shows which extension action or scheduled check produced the report. |
The shipped report builders read storage fields and post the report
function mu(e) {
chrome.storage.local.get(["uuid", "token", "loginRegion", "loginType", "userInfo", "lastRefreshUserInfoTime", "ipCountry", "extShareUnionId", "reportAgree"], (({
uuid: t,
token: n,
loginRegion: a,
loginType: r,
userInfo: i,
lastRefreshUserInfoTime: o,
ipCountry: s,
extShareUnionId: l,
reportAgree: c
}) => {
t = (t = t || "").length > 32 ? t.slice(0, 32) : t.padStart(32, "0");
const _ = f({
token: n,
ipCountry: s,
loginRegion: a
}),
d = {
bs: "bs",
sub_module: "TranslateAssistant",
appid: Number("US" === _ ? "132" : "113"),
unionid: Number(l) || Number("3000") || 1,
version: gu("1.2.0.2"),
pcid: t,
os_version: gu(Eu().version),
arch: 65535,
os_type: "mac" === bu() ? 5 : 1,
events: []
},
p = {
c_timestamp: Math.round(Date.now() / 1e3),
extend_fields: {
scene: 300,
param13: "3000"
}
};
if (s && (p.extend_fields.param10 = s), n && (p.extend_fields.param11 = (r || "wx") + "Login", null == i ? void 0 : i.user_id)) {
if (p.extend_fields.user_id = i.user_id + "", o && i.buy_right_package) {
const e = new Date - o;
e > 0 && (i.server_time += Math.round(e / 1e3), i.is_member = i.buy_right_package.some((e => e.unlimited || new Date(e.expire_at).getTime() / 1e3 > i.server_time)))
}
p.extend_fields.param1 = i.is_member ? 1 : 0
}
e.forEach((([e]) => {
var t, a;
"string" != typeof e && "number" != typeof e || (e = {
event_id: Number(e)
});
const r = Ap({}, p);
129 === e.event_id && n && (null == (a = null == (t = null == i ? void 0 : i.buy_right_package) ? void 0 : t[0]) ? void 0 : a.buy_time) && (r.extend_fields.param12 = i.buy_right_package[0].buy_time), e = Ap(r, e), d.events.push(e)
})), jp({
url: "https://translate-useraction-api.xiangtatech.com/api/v2/report",
type: "post",
noAppId: !0,
noToken: !0,
headers: {
"Content-Type": "application/json",
"Sign-Type": 0,
Business: "TranslateAssistant"
},
data: d,
success() {
e && e.forEach((([, e]) => {
"function" == typeof(null == e ? void 0 : e.success) && e.success()
})), e = null
},
error() {
e && e.forEach((([, e]) => {
"function" == typeof(null == e ? void 0 : e.error) && e.error()
})), e = null
}
})
}))
} function Rp(e) {
chrome.storage.local.get(["uuid", "token", "loginRegion", "loginType", "userInfo", "lastRefreshUserInfoTime", "ipCountry", "extShareUnionId", "reportAgree"], (({
uuid: t,
token: n,
loginRegion: a,
loginType: r,
userInfo: i,
lastRefreshUserInfoTime: o,
ipCountry: s,
extShareUnionId: l,
reportAgree: c
}) => {
t = (t = t || "").length > 32 ? t.slice(0, 32) : t.padStart(32, "0");
const _ = Ep({
token: n,
ipCountry: s,
loginRegion: a
}),
d = {
bs: "bs",
sub_module: "TranslateAssistant",
appid: Number("US" === _ ? "132" : "113"),
unionid: Number(l) || Number("3000") || 1,
version: vp("1.2.0.2"),
pcid: t,
os_version: vp(Np().version),
arch: 65535,
os_type: "mac" === yp() ? 5 : 1,
events: []
},
p = {
c_timestamp: Math.round(Date.now() / 1e3),
extend_fields: {
scene: 300,
param13: "3000"
}
};
if (s && (p.extend_fields.param10 = s), n && (p.extend_fields.param11 = (r || "wx") + "Login", null == i ? void 0 : i.user_id)) {
if (p.extend_fields.user_id = i.user_id + "", o && i.buy_right_package) {
const e = new Date - o;
e > 0 && (i.server_time += Math.round(e / 1e3), i.is_member = i.buy_right_package.some((e => e.unlimited || new Date(e.expire_at).getTime() / 1e3 > i.server_time)))
}
p.extend_fields.param1 = i.is_member ? 1 : 0
}
e.forEach((([e]) => {
var t, a;
"string" != typeof e && "number" != typeof e || (e = {
event_id: Number(e)
});
const r = _p({}, p);
129 === e.event_id && n && (null == (a = null == (t = null == i ? void 0 : i.buy_right_package) ? void 0 : t[0]) ? void 0 : a.buy_time) && (r.extend_fields.param12 = i.buy_right_package[0].buy_time), e = _p(r, e), d.events.push(e)
})), Tp({
url: "https://translate-useraction-api.xiangtatech.com/api/v2/report",
type: "post",
noAppId: !0,
noToken: !0,
headers: {
"Content-Type": "application/json",
"Sign-Type": 0,
Business: "TranslateAssistant"
},
data: d,
success() {
e && e.forEach((([, e]) => {
"function" == typeof(null == e ? void 0 : e.success) && e.success()
})), e = null
},
error() {
e && e.forEach((([, e]) => {
"function" == typeof(null == e ? void 0 : e.error) && e.error()
})), e = null
}
})
}))
}- translate-api.kangaroooffice.com
Observed vendor user-action report destination during dynamic analysis.
- translate-useraction-api.xiangtatech.com
User-action report host hardcoded in the shipped reporting functions.