Privacy Policy
Last updated: 5 November 2026. Versión en español.
Fluyo is two different things with two different data behaviours, and this policy treats them separately because conflating them would be misleading:
| The editor — fluyo.space | The MCP server — mcp.fluyo.space | |
|---|---|---|
| Does it receive your diagrams? | No. They never leave the browser | Yes. They travel over the network to the server |
| Does it store them? | Only on your own machine (localStorage) |
No. Processed in memory, then discarded |
| When does it apply? | Whenever you use the website | Only if you connect the remote server to your AI assistant |
If you only use the editor at fluyo.space and have never added the remote MCP connector, section B does not apply to you at all: the editor has not sent your diagrams to any server. The only thing that can take them off your machine is what you do with a file or a link.
Who is responsible
Fluyo is an open-source project maintained by itsnect (Claudio Jiménez Flores), based in Chile. It is not an incorporated company, sells nothing, has no customers and processes no payments.
Contact for any privacy matter: hello@fluyo.space. Further channels on the support page.
A. The editor at fluyo.space
The editor is a static file site. There is no application server, no database and no API of our own for the browser to call. Everything — drawing, animating, computing layout and encoding the GIF — happens on your machine, using your machine's processor.
Your diagrams
When you use the editor, they do not leave your browser. There is no backend for them to go to. When you click Save, the browser downloads a .fluyo.json file to your disk; when you click Open, it reads one from your disk. Neither involves a network request.
Diagrams that arrive in a link
There is a third route: a URL of the form fluyo.space/#d=… carries the diagram inside the link itself, compressed and encoded. It is what the MCP server returns so you can see the animated diagram without saving any file.
That content does not travel in the HTTP request. It sits after the hash, and browsers do not send a URL fragment: not in the request, not in the Referer header. You can check this yourself — serve the project locally, open one of these links and look at the access log: the line shows the path and nothing of the fragment. What does reach the server is what comes before the hash: the path and, if present, the query, such as ?ejemplo= or ?lang=, which do not carry your document. The content only reaches a server if you send it there explicitly, for example by giving the link or the document to the MCP server.
What you should know: the diagram is encoded, not encrypted. Anyone who receives the link can read it. It also stays in your browser history — which syncs across your devices if you have that turned on — and anywhere else you pass the link along. Share it with the same judgement you would apply to the file.
Share a copy through a link
The Share action asks for confirmation and generates fluyo.space/s/#d=… with a complete copy of the diagram. Anyone with the link can view it. The copy travels in the #d= fragment, so it does not go in the HTTP request either. Fluyo does not store this copy on a server and cannot revoke the link. Later changes in the editor do not modify the copy. The limit in this version is 64 KiB for the final URL; if it is exceeded, you can export the file.
Autosave
The current session is saved to your browser's localStorage, under the key fluyo.autosave.v1. That is local storage on your own machine, not a server: nobody else can read it, and it is erased when you clear site data in your browser.
Product analytics
The public site includes usage analytics served by Umami Cloud, without cookies and without identifying you by name or account, although Umami derives a session identifier.
What Fluyo sends is this closed list of events; automatic capture is off and there are no pageviews:
| Event | Meaning and properties |
|---|---|
editor_opened | Once per editor load. entry: direct, example (arrived with ?ejemplo=) or link (arrived with #d=), never the URL. returning: yes if this browser had opened Fluyo before, no otherwise (see “First visit”). locale: interface language (es, en, fr, ja, zh or other). |
first_edit_completed | First real change per editor load. Selection, pan, zoom, navigation, import and restore do not count. No properties. |
diagram_created | First edit that leaves nodes in a previously empty document, at most once per load. No properties. |
diagram_saved | Explicit download started from Save; not autosave, and no confirmation that it reached the disk. format: fluyo_json. |
diagram_exported | File generated and download started. format: gif, png, jpg or svg. No confirmation that it reached the disk. |
file_imported | A valid document was applied. source: file or link; format: fluyo_json. The source does not attribute MCP authorship. |
present_started | Presentation mode actually entered, even without full screen. No properties. |
example_loaded | A published example ended up open. example: identifier from the fixed list. source: url (?ejemplo=), menu (the “Example” button) or entry (the entry card). |
entry_chosen | First visit only: what was done with the entry card. choice: explore, blank or dismiss (Escape, touching the canvas or opening something else). |
story_created | A Story was created in the editor. origin: new, variant (“Another way from here” or “Duplicate as failure”) or copy (duplicate). Never its name or its sentences. |
story_started | A Story started playing. surface: editor or present. trigger: user or entry (started by the entry card). Once per playback, not per step. |
story_completed | That playback reached the end, watched or skipped through. surface: editor or present. Once per playback. |
gif_animation_added | anim: key of one of the eight built-in animations. |
link_failed | reason: decode, schema, too_large or unsupported. |
share_created | After confirming and actually creating a link within the limit. kind: story or diagram. variants: yes if its other ways travel with it, no otherwise. |
share_viewed | After the viewer's first successful render. story: yes if it carries a playable Story. locale: interface language, as above. |
viewer_story_started | In the viewer, when “Play” is pressed. No properties. |
viewer_story_completed | In the viewer, that playback reached the end. No properties. Once per playback. |
share_opened_in_editor | When “Open in Fluyo” is explicitly pressed in the viewer. No properties. |
What Umami gets from the request itself. Like any server, Umami receives your IP address and User-Agent. From them it records approximate country, region and city, browser, operating system and device type, and computes a session identifier using a hash of the site, the IP, the User-Agent and a salt that, according to Umami, rotates monthly by default. Also according to Umami, the IP is processed transiently for those calculations and not stored as a field in its analytics records, although Umami and its providers may record it in operational and security logs, separate from analytics. Whoever administers Fluyo can see this derived data and each session's sequence of events in Umami's dashboard, and consults it to understand how Fluyo is used. Fluyo sends Umami no user or account identifier and does not publish per-session activity. The session identifier avoids cookies, but it is not a guarantee of absolute anonymity.
First visit
The first time this browser opens the editor without a document in the link, a card over the canvas offers to watch an example in motion or to start blank. So that it is not offered again, the editor stores the key fluyo.seen with the value 1 in localStorage: no date, no identifier, and it is never sent. It does not appear either if any other fluyo.* key exists (saved session, theme or language). The only thing that leaves is its consequence, returning: yes/no in editor_opened; it counts browsers, not people: a private window, cleared site data or another device count as new.
The content of your diagrams is never sent to analytics. Only the events and values in these closed lists are accepted. The events carry no file or node names, text, images, prompts, document IDs or personal data. The comparison that detects the first edit happens only in local memory.
No private URLs are sent. Automatic capture is disabled with data-auto-track="false". Query and fragment are excluded with data-exclude-search and data-exclude-hash; on top of that, the data-before-send filter rebuilds the payload with a fixed path /, a fixed title Fluyo and an empty referrer. No additional automatic browser properties are sent. Asynchronous loading uses a bounded in-memory queue; blocking Umami does not stop you from working.
The analytics script loads only when the domain is fluyo.space or www.fluyo.space. If you clone the repository, open it locally or self-host it, that code never runs and no network call is made. Preview domains are deliberately excluded. The condition lives in js/analytics.js, in a single block, so you can verify it yourself.
If you want zero analytics: run the project locally or self-hosted, or block the cloud.umami.is domain. Fluyo works the same — the analytics code is written to fail silently.
The other external request
Besides the analytics script above, the editor makes a single request to a third party: it loads gif.js — and its gif.worker.js — from the cdnjs (Cloudflare) CDN; that is the library that encodes the GIF. It is a code download: none of your content is sent to it. As with any HTTP request, Cloudflare sees your IP address and user agent while serving the file. The service worker precaches it on first visit, so on later visits it is usually not even requested.
Umami serves its script from cloud.umami.is and receives the sanitized events at gateway.umami.is. These are the only third-party services the editor calls, and this list is complete: there are no external fonts, icons or stylesheets. Everything else is served from fluyo.space.
B. The MCP server at mcp.fluyo.space
Here is the part that needs saying plainly: the MCP server does receive the content of your diagrams over the network. This is unavoidable — it cannot edit or export a diagram it has not received — and it is the substantive difference from the editor.
This applies only if you have added https://mcp.fluyo.space/mcp as a remote connector in your AI assistant. If you run the server locally over stdio (npx fluyo-mcp), nothing leaves your machine and this section does not apply either.
What is received
- The diagram document your assistant sends: nodes, labels, colours, coordinates and, where present, images you embedded as data URIs.
- The arguments of the invoked tool — for example the label text when creating a diagram.
- Network metadata inherent to any HTTP request: your IP address (that of the calling client, which is normally your assistant's server rather than your own machine), request headers and the path.
How it is used and for how long
It is processed in memory and discarded. Each HTTP request builds a fresh server, handles the message and throws it away. There is no database, no disk, no cache and no sessions: the server is stateless by design, not by configuration. The document exists in the process's memory for as long as the request takes — milliseconds — and disappears with it.
The server does not store it, does not forward it to other services and does not use it to train anything. Since it runs on Cloud Run, the document passes through Google's infrastructure for the duration of the request.
The link it returns. Alongside the diagram, the tools return a fluyo.space/#d=… URL that opens it in the editor. It is built inside the same process from the document just received: no new request to anywhere, nothing stored, nothing logged. What that link means for whoever shares it is explained above, under Diagrams that arrive in a link.
What is logged
One line per request. A successful request looks like this:
{"ts":"2026-08-03T16:20:11.437Z","route":"/mcp","method":"POST",
"status":200,"outcome":"ok","durationMs":7,
"requestBytes":220,"responseBytes":472,"tools":["create_diagram"]}
When something fails, two more fields can appear, and neither carries content: toolErrors, which is how many tools returned an error — not which one, not why — and errorType, which is the error's class name (TypeError, ZodError…), never its message or its stack trace. Those nine fields plus the timestamp are the complete structure; there is no other.
No user data — document, labels, tool arguments, error messages, IP address — is written to the log. The name of the invoked tool is recorded, never its arguments; and if something fails, the log records that it failed and what class of error it was, never the value that caused it.
This does not rest on the discipline of whoever edits the code: the type describing a log line is a closed structure with no field that free text could occupy, and automated tests plant unrepeatable markers in a diagram's labels and fail if those markers appear in any log line. There is no debug mode that lifts these restrictions.
IP addresses and rate limiting
The server limits requests per IP address so that an open endpoint does not become an abuse or billing problem. For that purpose, and only that purpose, it keeps in RAM a record of the IP address and the timestamps of its recent requests.
- It is kept for the 60-second window of the limit, and expires on its own.
- There is a cap of 20,000 addresses held in memory at once; beyond that, the oldest are dropped.
- It is never written to disk. It is never written to the log. It dies when the instance is recycled.
- The IP address is read from the
x-forwarded-forheader, which the hosting platform rewrites. - It is used for nothing else: it does not identify, does not profile and does not decide permissions.
Authentication
The server asks for no credentials, creates no accounts and issues no tokens. There is nothing of yours on file because there is no sign-up.
Dependencies involved
No dependency was added for the HTTP transport: it uses Node's standard library. The dependency tree is the one already pulled in by the official Model Context Protocol SDK.
Of that whole tree, six packages actually load at runtime: @modelcontextprotocol/sdk, zod, @hono/node-server, ajv, ajv-formats and zod-to-json-schema. None of them persists anything and none of them makes outbound network requests. Their role is limited to routing the message, validating its shape and converting between request representations.
One honest detail: @hono/node-server, the component that adapts the HTTP request, may write connection errors to the console — ECONNRESET and similar, typical of a client that disconnects mid-response. Those messages are socket errors and contain no user data: they carry no document, no labels and no tool arguments.
Hosting platform logs
The two domains have different providers: fluyo.space is hosted on Vercel, and mcp.fluyo.space on Google Cloud, specifically on Cloud Run. Cloudflare resolves the DNS for fluyo.space, without acting as a proxy: HTTP requests to that domain do not go through it.
Vercel serves requests to the site, so it receives your IP address, the requested path with its query, your user agent and other headers. Its logs are of several kinds, and not all periods are confirmed. According to Vercel's documentation, on the Hobby plan Fluyo uses, runtime logs are kept for 1 hour. We have not confirmed a period for its request logs or its CDN requests, and we have not found a published one for its operational and security logs. When you use the editor, the content of your diagrams does not reach it, nor does the #d= fragment of a link.
As the MCP server's hosting provider, Google Cloud keeps its own platform logs in Cloud Logging, separate from the MCP server's and outside the control of this project's code. In the case of Cloud Run, the platform writes one log entry per request automatically, before the request reaches our code. Those logs include:
- The client IP address.
- The requested path and HTTP method.
- The response status code and its latency.
- The user agent and, if the request carries it, the
Referer.
Retention on Google Cloud: 7 days. This is not the default — Google Cloud Logging retains 30 days out of the box — but a value set explicitly on the _Default bucket. The exact command that sets it is published in the server's README, so this figure is verifiable rather than a promise.
They do not contain request bodies, so the content of your diagrams does not appear in them.
These logs should not be confused with the application log described above: they are two different things. The application log writes no user data at all, not even the IP address, and that stays true regardless of what happens to platform retention. Cloud Run's platform logs do contain the IP address, which is why they expire after 7 days.
For how Google handles that data as an infrastructure provider, see the Google Cloud privacy notice.
Who the data is shared with
Fluyo does not sell data and does not use it for advertising or to train models. The product does not read analytics data or make automated decisions about people with it. What Umami records per session and who consults it is described under “Product analytics”.
To work, the site needs hosting, resource delivery and analytics providers. When serving a request they receive information that can be personal, such as your IP address and User-Agent, and they process it to provide that service and under their own terms. This is what each one receives and why:
| Provider | What it receives | Why |
|---|---|---|
| Vercel | Requests to fluyo.space: IP, path with its query, user agent and other headers. According to Vercel, Hobby plan runtime logs are kept for 1 hour; the other periods are not confirmed | Hosting and delivery of the web application |
| Google Cloud | Requests to mcp.fluyo.space, with any document you send to the MCP server, which is processed in memory. Platform logs of those requests (IP, path, status, user agent) are retained 7 days and do not include the body | Hosting and running the MCP server |
| Umami Cloud | The events listed above (no pageviews), plus IP and User-Agent on the request, from which it derives approximate location, browser, operating system, device and a cookieless session identifier. Analytics record retention: 6 months, as Umami states for the Hobby plan Fluyo uses. | Usage analytics |
| Cloudflare | On cdnjs, the request for the gif.js files: IP and user agent. As DNS for fluyo.space, the resolution queries; not the HTTP requests | Delivery of the GIF library and DNS |
| Cloudflare and Google | Only if you write to hello@fluyo.space: your address and your message. Cloudflare receives them and forwards them to the project's Gmail account, where they are read and answered | Handling your enquiry |
In normal use of the editor, none of them receives the content of your diagrams. If you send a document to the MCP server, it reaches that server on Cloud Run, as section B explains. A link with #d= carries the diagram inside it: whoever opens it receives it, and so does any service you pass it through.
Children
Fluyo is not directed at children under 13 and does not knowingly collect data from them. Since there are no accounts and no sign-up, there is also no account that could belong to a child.
Your rights
The practical situation is unusual and worth stating as it is: there is no account of yours to access, rectify or erase, because Fluyo never asks for your name, email or sign-up.
- Your diagrams are on your machine. To delete them, delete the files and clear site data in your browser.
- The data that does exist outside your machine is the platform logs, with the retention stated above where it is confirmed; any operational and security logs Vercel, Umami or Cloudflare may have; and Umami's session records, described under “Product analytics”. Since they are not linked to an account, we normally cannot locate yours.
- Even so, if you wish to exercise any right of access, rectification, erasure, objection or portability, write to hello@fluyo.space and it will be handled.
Verify it yourself
What Fluyo's code does is checkable: the source of both parts is public and MIT-licensed.
- github.com/itsnect/fluyo — the editor. Analytics is isolated in
js/analytics.js. - github.com/itsnect/fluyo-mcp — the MCP server. What is and is not logged lives in
src/http-logging.ts; the per-IP limit, insrc/http-security.ts.
Changes to this policy
If it changes, the date in the header is updated and the change is recorded in the repository's public history, commit by commit. A change that materially affects what data is received will additionally be announced in the repository.
In case of discrepancy between translations, the Spanish version prevails.