[BUG] all js codes does not work (demo.launch(js=js)) if have PublicSpace -> Private Space

All js codes from lanch section will not work if you have public to private space.

If you satrt only private this very the same js code will work without a problem

1 Like

for now, general idea:


What’s really happening in your “Public Space → Private Space” setup

You are hitting two separate “gotchas” that look like one bug:

  1. You are not running the private Space’s frontend as-is.
    In almost every “public wrapper → private Space” pattern, the public Space uses gr.load("user/private-space", src="spaces", token=...) (or similar) to reconstruct the UI from the remote Space. In that mode, Gradio explicitly says it will NOT load high-level frontend attributes from the loaded Space, including custom js, css, and head. (Gradio)
    So any JS you added “in the private Space” will simply never be included when the public Space loads it.

  2. Hugging Face Spaces are cross-domain and iframe-heavy.
    When you open a Space via https://huggingface.co/spaces/<user>/<space>, Hugging Face embeds the actual app hosted on *.hf.space inside an iframe. Hugging Face documents that modern browsers restrict cookies in this setup. (Hugging Face)
    Once you combine “public wrapper” + “private app” you often create additional cross-origin boundaries that can break auth, assets, and anything relying on browser-side credentials.

Your own related thread about downloads shows the same architecture problem: a proxied URL chain from public → private (/gradio_api/proxy=...) is a strong sign you are in “rewritten, cross-origin, embedded” territory. (Hugging Face Forums)


Why it “works when only private” but “fails when public → private”

Private-only case

You visit the private Space directly. The private Space serves its own frontend. Your custom JS runs because it is part of that Space’s normal frontend boot.

Public → private case

Your public Space is now the thing serving the frontend. If you used gr.load() to “load the private Space,” Gradio reconstructs the interface but drops js/css/head from the loaded Space by design. (Gradio)
Result: “all JS codes from launch section do not work.”

That is expected behavior for gr.load().


One more important detail: demo.launch(js=...) is not the recommended way to add JS

Gradio’s guide states the “run JS on page load” mechanism is the js parameter on the Blocks or Interface initializer, not on launch(). (Gradio)

So even before Hugging Face enters the picture, the most version-stable pattern is:

import gradio as gr

js = """
() => {
  console.log("JS ran");
}
"""

with gr.Blocks(js=js) as demo:
    gr.Markdown("Hello")

demo.launch()

That aligns with Gradio’s own “Custom CSS and JS” guidance. (Gradio)


Causes in practice (ranked)

Cause A (most common): you’re using gr.load() and Gradio strips JS

If your public Space loads the private Space with gr.load(...), then your private Space’s js will not be carried over. This is explicitly documented. (Gradio)

Symptom:
The UI appears, inference might work, but your injected JS never runs.

Fix:
Put the JS in the public Space (the one actually rendering the UI), not in the loaded private Space. Or do not use gr.load() for UI composition.


Cause B: browser privacy settings block private Spaces in embedded/iframe contexts

Private Spaces often fail in strict privacy modes because cross-site cookies are blocked. Hugging Face documents the iframe cross-domain structure and cookie restrictions. (Hugging Face)
Users report fixing private Space loading by allowing third-party cookies for huggingface.co. (Hugging Face Forums)
Safari/iOS is a known pain point for private Spaces due to cross-site tracking prevention. (Hugging Face Forums)

Symptom:
The app loads partially, stays blank, or behaves inconsistently depending on browser. JS “doesn’t work” because the frontend never fully boots.

Fix:
Allow third-party cookies for huggingface.co, test Firefox, avoid Safari/iOS for private spaces, and test the direct *.hf.space URL. (Hugging Face Forums)


Cause C: visibility flip edge case breaks asset delivery (frontend JS bundle not loading)

There is a long-standing report: after switching a Space public → private and doing a factory reboot, the app doesn’t render and the console shows index.js 404. (Hugging Face Forums)

Symptom:
Nothing frontend-related works. Your JS won’t run because the main JS bundle is missing.

Fix:
Avoid factory reboot right after visibility flip. Try normal restart, clear cache, redeploy. If you see index.js 404, you are debugging build/asset delivery, not your JS logic. (Hugging Face Forums)


Solutions that actually work

Solution 1: Treat the private Space as a backend API. Build the UI (and JS) in the public Space.

This is the cleanest pattern.

  • Public Space renders the UI. Put your JS there using Blocks(js=...). (Gradio)
  • Public Space calls private Space server-to-server using a token stored as a Space Secret. HF community guidance: a Space does not automatically inherit your user permissions, you must pass a token, typically via Authorization: Bearer ... and store it in secrets. (Hugging Face Forums)
  • Use gradio_client from Python to call private Spaces with hf_token. Gradio’s python client docs show this directly. (Gradio)

This avoids the gr.load() “JS is dropped” behavior because you are not trying to transplant the private Space frontend.


Solution 2: If you insist on gr.load(), accept that private Space JS will not come through

This is not a “maybe.” It is documented behavior: loaded Space high-level attributes (js/css/head) will not be loaded. (Gradio)

So your choices are:

  • duplicate the JS logic into the wrapper Space
  • or avoid relying on custom JS entirely
  • or stop using gr.load() and build a single Space

Solution 3: If your goal is embedding, remember embedding requires public visibility

Hugging Face’s embed documentation says to embed a Space its visibility must be public, and also explains the direct https://<space-subdomain>.hf.space URL. (Hugging Face)
That requirement is exactly why people invent “public wrapper → private Space” patterns, which then trigger the gr.load() limitations and cross-origin problems.

If you need “private but embeddable,” you typically move to:

  • public Space with app-level auth (OAuth, password gate, etc.), or
  • a custom site that calls a private backend API

Quick troubleshooting checklist (fast and decisive)

  1. Are you using gr.load() in the public Space?
    If yes, your private Space js will not be included. This alone explains your symptom. (Gradio)

  2. Does the private Space run your JS when visited directly?
    If yes, your JS is fine. The wrapper architecture is the issue.

  3. Open DevTools. Look for index.js 404 or other asset failures.
    If present, it’s an asset/render failure after visibility flip. (Hugging Face Forums)

  4. Test browser privacy settings.
    If private spaces behave differently across browsers, it is likely iframe cookie restrictions. (Hugging Face)


Summary

  • If your public Space loads the private Space with gr.load(), the loaded Space’s js/css/head are intentionally not loaded. That is the main cause. (Gradio)
  • Correct “run JS on load” pattern is Blocks(js=...) or Interface(js=...), not relying on launch(js=...). (Gradio)
  • Private + embedded contexts add iframe and cookie restrictions that can prevent the frontend from booting at all in some browsers. (Hugging Face)
  • Best fix: render UI in the public Space and call the private Space as an API using a secret token and gradio_client. (Gradio)
1 Like

Gradio <=5.49.1 JS in Blocks(js=…) or Interface(js=…)

Gradio >=6 JS/theme/head/css/ are moved in Launch(js=…)

Perfect=clean & fast &reliable solution => works great!!!
Thank you so much!

1 Like

This topic was automatically closed 12 hours after the last reply. New replies are no longer allowed.