{"course":{"slug":"hugging-face","title":"Hugging Face, End to End","url":"https://addaly.com/learn/hugging-face","level":"intermediate","track":"create"},"lesson":{"slug":"calling-a-space-as-an-api","title":"Every Space is an API you can call","url":"https://addaly.com/learn/hugging-face/calling-a-space-as-an-api","position":36,"of":75,"minutes":8,"answer":"Gradio exposes every event handler as an API endpoint automatically, so any public Space is a callable service, but it can sleep, change or vanish and you cannot see its logs.","keyIdea":"Gradio exposes every event handler as an API endpoint automatically, so any public Space is a callable service, but it can sleep, change or vanish and you cannot see its logs, so anything you depend on should be a private duplicate you control."},"body":{"format":"markdown","text":"## The feature almost nobody uses\n\nScroll to the bottom of any Gradio Space and there is a link reading **Use via API**. Click it. You get the endpoint names, the parameter types, and working code in Python and JavaScript.\n\nThis is not an extra somebody configured. Gradio exposes every event handler as an endpoint automatically. Which means: any public Space is a hosted service you can call from your own code, without deploying anything, without a key beyond a Hub token, and without the model being on your machine.\n\n```bash\npip install gradio_client\n```\n\n```python\nfrom gradio_client import Client\n\nclient = Client(\"abidlabs/whisper\")\nresult = client.predict(\"audio.wav\", api_name=\"/predict\")\nprint(result)\n```\n\nFiles work too, in both directions:\n\n```python\nfrom gradio_client import Client, handle_file\n\nclient = Client(\"your-name/your-space\")\nout = client.predict(\n    image=handle_file(\"https://example.com/photo.jpg\"),\n    threshold=0.5,\n    api_name=\"/segment\",\n)\n```\n\n`handle_file` takes a local path or a URL and does the upload. The result is a path to a downloaded file in a temporary directory.\n\n## Long jobs, without blocking\n\n```python\njob = client.submit(\"a long prompt\", api_name=\"/generate\")\nwhile not job.done():\n    print(job.status())\nprint(job.result())\n```\n\n`submit` returns immediately and the job reports queue position and progress. This is what you want inside a web application, where blocking for ninety seconds is not an option.\n\n## The honest limits\n\nCalling somebody else's Space is convenient and it is not a service level agreement:\n\n- **It can be deleted or changed** at any moment, by someone who owes you nothing.\n- **It can be asleep**, so your first call waits out a cold start.\n- **It is queued**, behind everyone else on the internet using it.\n- **Your input goes to their container**, and you do not know what they log. Never send personal or confidential data to a Space you do not own. This is the same judgement you would apply to any third-party API, and the informality of the Hub makes people forget it.\n\nThe responsible pattern is to **duplicate the Space first**, privately, and call your copy. You then control the hardware, the sleep policy and the data, at the cost of the hardware bill. For a Space you rely on, this is not optional.\n\n## Naming your own endpoints\n\nIf you want your Space to be callable, name the endpoints:\n\n```python\nbtn.click(fn=transcribe, inputs=[audio], outputs=[text], api_name=\"transcribe\")\nother.click(fn=internal_helper, inputs=[x], outputs=[y], api_name=False)\n```\n\n`api_name=\"transcribe\"` gives a stable `/transcribe` route that survives layout changes. `api_name=False` hides a handler from the API entirely, which you want for anything that is a UI detail rather than a capability.\n\nA Space with named endpoints and an honest readme is a small, free, public service. That is a useful thing to publish, and it costs one keyword argument.\n\n## Private Spaces need a token\n\nA private Space, or one on gated hardware, needs authentication on every call:\n\n```python\nclient = Client(\"your-name/private-space\", hf_token=os.environ[\"HF_TOKEN\"])\n```\n\nRead the token from the environment rather than writing it in the script, for the reasons the tokens lesson sets out. A fine-grained token scoped to that one repository is better than an account-wide one, because a token that leaks from a client is a token that can be revoked without breaking everything else you own.\n\n## The MCP option\n\nGradio can expose a Space's functions as an MCP server, so an AI assistant that speaks the protocol can call your Space as a tool:\n\n```python\ndemo.launch(mcp_server=True)\n```\n\nThe function signature and docstring become the tool description, which means type hints and a clear docstring stop being style and start being interface. Whether you use this or not, it is worth knowing that the same Space can be a web page, a REST endpoint and a tool for an agent with no additional code.\n\n## When not to do any of this\n\nIf you are calling a Space in a loop over ten thousand items, stop. You are using somebody's free demo hardware as a batch processor, which is rude, slow, and will be rate limited. Run the model yourself, duplicate the Space onto hardware you pay for, or use an inference provider. Spaces are for demonstration and light use; the platform's terms say as much.\n\n## Do this now\n\nPick any public Space that does something you need, open Use via API, and call it from a Python script. Then decide honestly whether you should be calling theirs or duplicating it, and if the answer is duplicate, do that instead."},"check":{"question":"A startup builds a product feature on `gradio_client` calls to a stranger's public Space. What is the most serious problem with this, beyond reliability?","options":[{"text":"Gradio endpoints are not versioned, so a layout change in the Space renames the route and breaks the integration.","correct":false,"tempting":"A real fragility, and one that `api_name` is designed to prevent from the Space owner's side."},{"text":"Free Space hardware rate limits by IP, so production traffic will be throttled after a few hundred calls.","correct":false,"tempting":"Throttling is likely, but it is a reliability constraint of the same kind already set aside in the question."},{"text":"Customer data is being sent to a container owned by someone with no obligations and unknown logging.","correct":true},{"text":"Calls through gradio_client bypass the queue, so the Space's owner sees degraded service for their own users.","correct":false,"tempting":"API calls enter the same queue as web users rather than bypassing it."}]},"prev":{"slug":"beyond-gradio","title":"Streamlit, Docker and a Space with no server at all","url":"https://addaly.com/learn/hugging-face/beyond-gradio"},"next":{"slug":"debugging-a-space","title":"It built, it started, it is red","url":"https://addaly.com/learn/hugging-face/debugging-a-space"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Every Space is an API you can call', in Hugging Face, End to End. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/hugging-face/calling-a-space-as-an-api (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Every Space is an API you can call","courseTitle":"Hugging Face, End to End","module":{"index":4,"slug":"spaces-and-shipping-something","title":"Spaces: putting something in front of people"},"answer":null,"keyIdea":"Gradio exposes every event handler as an API endpoint automatically, so any public Space is a callable service, but it can sleep, change or vanish and you cannot see its logs, so anything you depend on should be a private duplicate you control.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-feature-almost-nobody-uses","runs":[{"text":"The feature almost nobody uses"}]},{"t":"p","runs":[{"text":"Scroll to the bottom of any Gradio Space and there is a link reading "},{"text":"Use via API","b":true},{"text":". Click it. You get the endpoint names, the parameter types, and working code in Python and JavaScript."}]},{"t":"p","runs":[{"text":"This is not an extra somebody configured. Gradio exposes every event handler as an endpoint automatically. Which means: any public Space is a hosted service you can call from your own code, without deploying anything, without a key beyond a Hub token, and without the model being on your machine."}]},{"t":"code","lang":"bash","label":"Bash","text":"pip install gradio_client"},{"t":"code","lang":"python","label":"Python","text":"from gradio_client import Client\n\nclient = Client(\"abidlabs/whisper\")\nresult = client.predict(\"audio.wav\", api_name=\"/predict\")\nprint(result)"},{"t":"p","runs":[{"text":"Files work too, in both directions:"}]},{"t":"code","lang":"python","label":"Python","text":"from gradio_client import Client, handle_file\n\nclient = Client(\"your-name/your-space\")\nout = client.predict(\n    image=handle_file(\"https://example.com/photo.jpg\"),\n    threshold=0.5,\n    api_name=\"/segment\",\n)"},{"t":"p","runs":[{"text":"handle_file","code":true},{"text":" takes a local path or a URL and does the upload. The result is a path to a downloaded file in a temporary directory."}]},{"t":"h2","id":"long-jobs-without-blocking","runs":[{"text":"Long jobs, without blocking"}]},{"t":"code","lang":"python","label":"Python","text":"job = client.submit(\"a long prompt\", api_name=\"/generate\")\nwhile not job.done():\n    print(job.status())\nprint(job.result())"},{"t":"p","runs":[{"text":"submit","code":true},{"text":" returns immediately and the job reports queue position and progress. This is what you want inside a web application, where blocking for ninety seconds is not an option."}]},{"t":"h2","id":"the-honest-limits","runs":[{"text":"The honest limits"}],"role":"limit"},{"t":"p","runs":[{"text":"Calling somebody else’s Space is convenient and it is not a service level agreement:"}]},{"t":"ul","items":[[{"text":"It can be deleted or changed","b":true},{"text":" at any moment, by someone who owes you nothing."}],[{"text":"It can be asleep","b":true},{"text":", so your first call waits out a cold start."}],[{"text":"It is queued","b":true},{"text":", behind everyone else on the internet using it."}],[{"text":"Your input goes to their container","b":true},{"text":", and you do not know what they log. Never send personal or confidential data to a Space you do not own. This is the same judgement you would apply to any third-party API, and the informality of the Hub makes people forget it."}]]},{"t":"p","runs":[{"text":"The responsible pattern is to "},{"text":"duplicate the Space first","b":true},{"text":", privately, and call your copy. You then control the hardware, the sleep policy and the data, at the cost of the hardware bill. For a Space you rely on, this is not optional."}]},{"t":"h2","id":"naming-your-own-endpoints","runs":[{"text":"Naming your own endpoints"}]},{"t":"p","runs":[{"text":"If you want your Space to be callable, name the endpoints:"}]},{"t":"code","lang":"python","label":"Python","text":"btn.click(fn=transcribe, inputs=[audio], outputs=[text], api_name=\"transcribe\")\nother.click(fn=internal_helper, inputs=[x], outputs=[y], api_name=False)"},{"t":"p","runs":[{"text":"api_name=\"transcribe\"","code":true},{"text":" gives a stable "},{"text":"/transcribe","code":true},{"text":" route that survives layout changes. "},{"text":"api_name=False","code":true},{"text":" hides a handler from the API entirely, which you want for anything that is a UI detail rather than a capability."}]},{"t":"p","runs":[{"text":"A Space with named endpoints and an honest readme is a small, free, public service. That is a useful thing to publish, and it costs one keyword argument."}]},{"t":"h2","id":"private-spaces-need-a-token","runs":[{"text":"Private Spaces need a token"}]},{"t":"p","runs":[{"text":"A private Space, or one on gated hardware, needs authentication on every call:"}]},{"t":"code","lang":"python","label":"Python","text":"client = Client(\"your-name/private-space\", hf_token=os.environ[\"HF_TOKEN\"])"},{"t":"p","runs":[{"text":"Read the token from the environment rather than writing it in the script, for the reasons the tokens lesson sets out. A fine-grained token scoped to that one repository is better than an account-wide one, because a token that leaks from a client is a token that can be revoked without breaking everything else you own."}]},{"t":"h2","id":"the-mcp-option","runs":[{"text":"The MCP option"}]},{"t":"p","runs":[{"text":"Gradio can expose a Space’s functions as an MCP server, so an AI assistant that speaks the protocol can call your Space as a tool:"}]},{"t":"code","lang":"python","label":"Python","text":"demo.launch(mcp_server=True)"},{"t":"p","runs":[{"text":"The function signature and docstring become the tool description, which means type hints and a clear docstring stop being style and start being interface. Whether you use this or not, it is worth knowing that the same Space can be a web page, a REST endpoint and a tool for an agent with no additional code."}]},{"t":"h2","id":"when-not-to-do-any-of-this","runs":[{"text":"When not to do any of this"}]},{"t":"p","runs":[{"text":"If you are calling a Space in a loop over ten thousand items, stop. You are using somebody’s free demo hardware as a batch processor, which is rude, slow, and will be rate limited. Run the model yourself, duplicate the Space onto hardware you pay for, or use an inference provider. Spaces are for demonstration and light use; the platform’s terms say as much."}]},{"t":"h2","id":"do-this-now","runs":[{"text":"Do this now"}],"role":"try"},{"t":"p","runs":[{"text":"Pick any public Space that does something you need, open Use via API, and call it from a Python script. Then decide honestly whether you should be calling theirs or duplicating it, and if the answer is duplicate, do that instead."}]}],"check":{"question":[{"text":"A startup builds a product feature on "},{"text":"gradio_client","code":true},{"text":" calls to a stranger’s public Space. What is the most serious problem with this, beyond reliability?"}],"options":[{"text":[{"text":"Gradio endpoints are not versioned, so a layout change in the Space renames the route and breaks the integration."}],"correct":false,"tempting":[{"text":"A real fragility, and one that "},{"text":"api_name","code":true},{"text":" is designed to prevent from the Space owner’s side."}]},{"text":[{"text":"Free Space hardware rate limits by IP, so production traffic will be throttled after a few hundred calls."}],"correct":false,"tempting":[{"text":"Throttling is likely, but it is a reliability constraint of the same kind already set aside in the question."}]},{"text":[{"text":"Customer data is being sent to a container owned by someone with no obligations and unknown logging."}],"correct":true,"tempting":null},{"text":[{"text":"Calls through gradio_client bypass the queue, so the Space’s owner sees degraded service for their own users."}],"correct":false,"tempting":[{"text":"API calls enter the same queue as web users rather than bypassing it."}]}],"order":[3,1,0,2],"why":null},"prev":{"slug":"beyond-gradio","title":"Streamlit, Docker and a Space with no server at all","minutes":8},"next":{"slug":"debugging-a-space","title":"It built, it started, it is red","minutes":8}}}