Cursive Translator

Privacy

Privacy at Cursive Translator

This page describes the request path written into this site's own code, and stops there. This site has no account system or image-and-transcript database; an image you submit is posted to a Cloudflare Pages Function and forwarded to Google Cloud Vision; and every page of this site includes the Google Analytics tag. The endpoint does use KV for request counters and alert throttling, as described below. What Cloudflare and Google do with a request once it reaches them is governed by their own current policies, and this page does not summarise, paraphrase or vouch for those policies.

Effective date: 14 August 2026. That is a label showing when this text was last revised. It is not a statement about any third-party service's behaviour at any time.

The short version

  • No accounts. This site publishes no sign-up, sign-in or account page, and its code contains no user record.
  • No image or transcript database. The site code does not intentionally persist either item. Its separate KV use is limited to the request counters, operational counters and alert-throttle keys described below.
  • An uploaded image leaves your device. Your browser posts it to a Cloudflare Pages Function on this site, and that function forwards it to Google Cloud Vision.
  • The text-to-handwriting drawing script sends neither typed text nor the canvas. It calls local canvas APIs and attempts PNG export without a fetch, upload or endpoint in that drawing code path. The page still loads the analytics code described below.
  • The analytics tag is on every page. Each of the fourteen HTML pages of this site — the thirteen published URLs and the 404 page — includes the Google Analytics tag with the site's configured GA4 measurement ID.
  • The endpoint reads an IP header. The Function reads the CF-Connecting-IP header for configured per-IP checks. It keeps recent timestamps in module-isolate memory and attempts to write counter keys of the form ip:<ip>:<UTC date> into a key-value store with a two-day expiry.
  • Do not upload sensitive material. Site policy, stated in full below.

What happens when you transcribe an image

The three upload pages — the cursive translator, handwriting to text and decipher handwriting — load the same script and post to the same endpoint. Pressing the read button runs this sequence, as written in the code:

  • Your browser reads the file locally. The selected image is read with FileReader as a data URL and the base64 portion is taken. Files over 6 MB are rejected in the browser and never sent.
  • Your browser posts it to this site. A JSON body of the form {"image": "<base64>"} is posted to /api/cursive-to-text, which is a Cloudflare Pages Function.
  • The Function forwards the image to Google Cloud Vision. It sends one request to vision.googleapis.com/v1/images:annotate with feature DOCUMENT_TEXT_DETECTION and language hint en.
  • The text field of the response returns to your browser and is written into the editable box on the page. It exists in that page while the page is open.
  • The site code does not intentionally persist either. There is no write of your image or the returned text to a store belonging to this site. The endpoint also writes numeric request and operational counters plus alert-throttle keys; their keys may contain an IP address and date, but not the image or returned text.

What this site does not state about the two companies involved

Once a request reaches Cloudflare or Google it is handled on their systems, under their own current terms and policies. This page does not describe, summarise or paraphrase what either company does with it, does not state that anything is or is not retained there, and gives no deletion timetable. Read their policies at the source if you need to know; those documents are their own statement of their handling, and they change without reference to this site.

Google publishes its policy at policies.google.com/privacy (external resource; contents not verified in this build).

"The site code does not intentionally persist" is a statement about this repository's own code and nothing else. It is not a retention period, and it says nothing about any system the request passes through.

Please do not upload sensitive material

A handwritten page can carry names and addresses, dates of birth, medical notes, financial figures, identification numbers, and information about people other than you who did not choose to have their letter sent to a recognition service.

An uploaded image is sent off your device to an external service. This site therefore asks you to observe the following, as policy:

  • Crop before you upload. Submit only the passage you need read, not the whole letterhead, signature block and margin.
  • Mask what you do not need read. Anything you cover before capture is not in the request at all.
  • Do not upload medical, legal, financial or identity documents. If a page would be a problem in the wrong hands, transcribe it by hand instead of submitting it here.
  • Do not upload another person's private correspondence without their agreement.
  • The upload path does not apply to text to handwriting. Its drawing script contains no request that sends the typed text or canvas, but the page-level analytics request described above remains present.

The text-to-handwriting tool runs in your browser

The text to handwriting page loads a separate script that contains no fetch, no form submission and no endpoint. It draws your typed text onto an HTML canvas element in your browser using the font names written into the page, and Download PNG calls canvas.toDataURL and clicks a local link. The text you type is not posted to this site, to the Pages Function or to Google Cloud Vision.

The page-level items still apply while you are on it: that page carries the same analytics tag as every other page, and the HTTP request for the page itself is an ordinary request to the host. What the code does not do is transmit the text you type or the sheet it draws.

Analytics

What is in this site's code: every one of the fourteen HTML pages in this repository — the thirteen published URLs plus the 404 page — contains, in its <head>, a script tag loading googletagmanager.com/gtag/js with the site's configured GA4 measurement ID, followed by the standard gtag('js', …) and gtag('config', …) calls using that same ID. That is the whole of the analytics code on this site. No other identifier, event, user ID or custom parameter is passed to it anywhere in this repository, and no account is linked to it, because this site has no accounts.

What is collected once that script has loaded, whether cookies or other local identifiers are set, and how the resulting data is processed are determined by Google Analytics. This page does not describe or summarise that behaviour. If the script does not load — a blocker, a browser setting, an extension, a network policy — this site's own code neither detects that nor works around it, and the tools on this site do not reference the analytics code at all.

Two external references, listed as links only:

Neither link is quoted or summarised here. Read them at the source.

What the endpoint does with your IP address

The request-handling code on this site reads two things about your request beyond the image itself: the Origin header, which it compares against the site's own host and rejects if it does not match, and the CF-Connecting-IP header, which it uses for limits.

  • An in-memory per-IP branch. The Function keeps recent request timestamps per IP in module-isolate memory and has an HTTP 429 branch above 10 requests per IP per 60 seconds. Isolates do not share this memory, so this is not a stable distributed rate limit.
  • Daily KV counters. It attempts to read and increment two counters in a key-value store: one global, keyed g:<UTC date>, and one per address, keyed ip:<ip>:<UTC date>. Writes request a two-day expiry. Values of 3000 site-wide and 100 per IP per UTC day are rejection thresholds in the code. Reads and writes fail open, and increments use non-atomic read-modify-write operations, so these are best-effort controls rather than hard caps.
  • Operational counters and alerts. Error and block counts per date and alert-throttle keys are written in the same store. An alert message containing the IP address may be sent to an operations webhook when a configured rejection branch fires or the upstream service returns an error; rejection alerts also include the applicable request counts.
  • No image or returned text in those KV entries. Values are numeric strings. Key shapes are global or per-IP daily counters, daily operational counters, and prefixed alert-throttle identifiers. Per-IP counters and some per-IP alert-throttle identifiers contain an IP address; the other shapes do not.

Page requests pass through external hosting and network infrastructure. This page makes no claim about whether or how those providers log a request; consult their current policies for their own description.

Email sent to the published address

The address published on this site is [email protected], and the contact page states what to include. The link asks your device to open its configured mail handler. If you send a message, it is handled outside these web pages; this page makes no claim about how the mailbox or mail route is hosted, secured or retained. Do not include material you are unwilling to send by email.

Two requests, as site policy: when reporting a fault, state the browser and the exact text shown on screen; and do not attach the document you were trying to transcribe.

What this site leaves under your control

This site has no account and therefore no settings screen. Two facts about its own code bear on what you can do:

  • The tools do not reference the analytics code. Neither ocr.js nor reverse.js reads gtag, dataLayer or any analytics value, so whether the analytics script loads has no effect on either tool's behaviour.
  • Typed text stays outside the drawing script's requests. On text to handwriting, that script sends neither typed text nor canvas data; page-level analytics remains disclosed above.

Beyond that, the controls are in software this site does not operate: your browser's own cookie, storage and script settings; any blocker or extension you install; and the opt-out add-on and account settings published by Google. This page does not describe what any of those do — read each at its source and test the result yourself.

Requests about data held by Cloudflare or Google go to those companies. This site holds no copy of your image or transcript to search, correct or delete, and cannot act on their behalf.

What this site does not have, and what it does not claim

  • No accounts, logins or user profiles. No page here registers, authenticates or identifies a visitor.
  • No payments. No page here collects a card or billing detail, and no payment code is present.
  • No user-generated public pages. Nothing you upload or type is published, listed or made visible to another visitor by this site's code.
  • No transcript archive. The site code has no transcript database and provides no saved-work or history retrieval feature.
  • No claim about third-party retention. This page does not assert that Cloudflare or Google store anything or nothing, and states no deletion deadline for any system outside this repository.
  • No compliance claim. This page is a description of this site's own code and policy. It is not a certification of GDPR, CCPA or any other regulatory status, and it is not legal advice.

This site is published for a general audience and is not directed at children. Use of the pages is also governed by the terms, and the about page states what the tools consist of.

Changes, and the published address

This page carries an effective date and no version history. There is no mailing list and no notification mechanism on this site, so this page as served is the only statement available to you. Read it again if the terms of your use of the site depend on it.

Questions about anything on this page go to [email protected]; the contact page states what to include. No reply time and no outcome are undertaken.