{"id":2003,"date":"2025-08-14T15:56:14","date_gmt":"2025-08-14T15:56:14","guid":{"rendered":"https:\/\/www.pyxll.com\/blog\/?p=2003"},"modified":"2025-08-14T15:58:14","modified_gmt":"2025-08-14T15:58:14","slug":"long-running-excel-functions","status":"publish","type":"post","link":"https:\/\/www.pyxll.com\/blog\/long-running-excel-functions\/","title":{"rendered":"Long Running Excel Functions"},"content":{"rendered":"\n<p>Hit <em>Enter<\/em>, and your formula runs\u2026 but Excel is locked solid. No scrolling. No edits. Just waiting.<\/p>\n\n\n\n<p>With <strong>PyXLL<\/strong>, it doesn\u2019t have to be that way. You can run long Python functions without freezing Excel \u2014 and even show live progress updates while they work.<\/p>\n\n\n\n<p>Here\u2019s how.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<span class=\"embed-youtube\" style=\"text-align:center; display: block;\"><iframe loading=\"lazy\" class=\"youtube-player\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/4f20XpK4SHo?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en-US&#038;autohide=2&#038;wmode=transparent\" allowfullscreen=\"true\" style=\"border:0;\" sandbox=\"allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox\"><\/iframe><\/span>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-what-is-a-long-running-function\">What is a long running function?<\/h2>\n\n\n\n<p>Ever written an Excel function that takes so long to run it feels like Excel has frozen?<br>Normally, when a function is running, Excel just sits there \u2014 locked up until the function finishes. Not fun.<\/p>\n\n\n\n<p>With <strong><a href=\"https:\/\/www.pyxll.com\" target=\"_blank\" rel=\"noreferrer noopener\">PyXLL<\/a><\/strong>, we can break free from that limitation. It\u2019s possible to write Python functions that run in the background, letting Excel stay responsive while the work gets done.<\/p>\n\n\n\n<p>PyXLL lets you call Python functions directly from Excel as if they were ordinary worksheet formulas. But what happens when those Python functions are slow \u2014 really slow \u2014 and nobody wants to watch the spreadsheet grind away?<\/p>\n\n\n\n<p>You can try to make the code faster (see <a href=\"https:\/\/www.pyxll.com\/blog\/how-to-profile-python-code-in-excel\/\">How to profile Python code in Excel<\/a>), but sometimes speed just isn\u2019t in your control \u2014 for example, when pulling huge datasets from a database or waiting on a sluggish web service.<\/p>\n\n\n\n<p>In this article, we\u2019ll look at a couple of ways to make slow Python functions in Excel feel fast \u2014 or at least, feel painless \u2014 by improving the user experience instead of the raw execution time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-sample-problem\">Sample Problem<\/h2>\n\n\n\n<p>Let\u2019s start with a simple example of a slow function.<\/p>\n\n\n\n<p>I\u2019ve written a small demo that returns one of Plotly\u2019s standard test datasets \u2014 nothing too fancy.<\/p>\n\n\n\n<p>To really make the function \u201cslow\u201d, I\u2019ve sprinkled in a few <code>time.sleep<\/code> calls. (Think of them as coffee breaks for your code.)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from pyxll import xl_func\nimport plotly.data\nimport time\n\n@xl_func(\"str dataset: dataframe\")\ndef long_running_function(dataset: str):\n    \"\"\"Runs synchronously, blocking Excel.\"\"\"\n    for i in range(50):\n        time.sleep(0.05)\n\n    func = getattr(plotly.data, dataset)\n    return func()<\/pre>\n\n\n\n<p>Now, when we run this function in Excel, the problem jumps out immediately: while the function is running, Excel is completely frozen. You can\u2019t scroll, edit cells, or keep working \u2014 you\u2019re stuck waiting. Even worse, if you change any input to the function, Excel blocks again until it\u2019s done.<\/p>\n\n\n\n<p>The result? A spreadsheet that feels sluggish and frustrating to use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-async-to-the-rescue\"><strong>Async to the Rescue<\/strong><\/h2>\n\n\n\n<p>The first way to tackle our slow-function problem is with an <strong>async function<\/strong> (see <a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/udfs\/asyncfuncs.html\" target=\"_blank\" rel=\"noreferrer noopener\">Asynchronous Functions<\/a>).<\/p>\n\n\n\n<p>In Excel, async functions run concurrently. If you\u2019ve got multiple async functions on a sheet, Excel will kick them all off at once, then wait until they\u2019re all done. This is perfect for firing off lots of small web or database requests in parallel \u2014 but it\u2019s also handy for big, slow jobs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-using-asyncio-with-pyxll\">Using <code>asyncio<\/code> with PyXLL<\/h3>\n\n\n\n<p>With PyXLL, the easiest way to write an async Excel function is to use Python\u2019s built-in <code><a href=\"https:\/\/docs.python.org\/3\/library\/asyncio.html\">asyncio<\/a><\/code>. I\u2019m not going to dive deep into async programming or threading here \u2014 if you\u2019re new to those topics, I\u2019d suggest checking out some tutorials first so you can get the most from this example.<\/p>\n\n\n\n<p>Let\u2019s take our original slow function and convert it into an async one. Async really shines when you can <em>yield<\/em> control back to the event loop while you\u2019re waiting on something \u2014 typically I\/O like a database query or an API call. Instead of blocking with <code>time.sleep<\/code>, we\u2019ll swap that for <code>await asyncio.sleep<\/code>, which does the same thing but lets other work happen in the meantime.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from pyxll import xl_func\nimport plotly.data\nimport asyncio\n\n@xl_func(\"str dataset: dataframe\")\nasync def long_running_function_async(dataset):\n    \"\"\"Runs on the asyncio event loop.\"\"\"\n    for i in range(50):\n        await asyncio.sleep(0.05)\n\n    func = getattr(plotly.data, dataset)\n    return func()<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-user-experience-in-excel\">User Experience in Excel<\/h3>\n\n\n\n<p>Back in Excel, when we call our new async function, things look similar at first \u2014 Excel still waits for the result. But there\u2019s an important difference: if the user tries to click around while the calculation is running, Excel interrupts it with a <code>#CALC!<\/code> error, allowing them to keep working. Behind the scenes, our function is still running, and once it finishes, Excel quietly updates the cell with the result.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image.png\"><img decoding=\"async\" width=\"1024\" height=\"550\" data-attachment-id=\"2015\" data-permalink=\"https:\/\/www.pyxll.com\/blog\/long-running-excel-functions\/image-39\/\" data-orig-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image.png\" data-orig-size=\"1291,694\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1024x550.png\" src=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1024x550.png\" alt=\"Long running async Excel function showing a #CALC! error\" class=\"wp-image-2015\" srcset=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1024x550.png 1024w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-300x161.png 300w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-768x413.png 768w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image.png 1291w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-when-async-isn-t-enough\">When Async Isn\u2019t Enough<\/h3>\n\n\n\n<p>Of course, not every function can be easily rewritten as async. In some cases, it\u2019s better to run the work on a <em>background thread<\/em> or even a separate <em>process<\/em>. One easy way to do this in Python is with the <code><a href=\"https:\/\/docs.python.org\/3\/library\/concurrent.futures.html#threadpoolexecutor\" target=\"_blank\" rel=\"noreferrer noopener\">ThreadPoolExecutor<\/a><\/code> or <code><a href=\"https:\/\/docs.python.org\/3\/library\/concurrent.futures.html#processpoolexecutor\">ProcessPoolExecutor<\/a><\/code> from the <code>concurrent.futures<\/code> module. Paired with <code>asyncio<\/code>\u2019s <code><a href=\"https:\/\/docs.python.org\/3\/library\/asyncio-eventloop.html#asyncio.loop.run_in_executor\" target=\"_blank\" rel=\"noreferrer noopener\">run_in_executor<\/a><\/code>, you can offload a slow function to a background thread or process while keeping the async structure in place.<\/p>\n\n\n\n<p>Here\u2019s what that looks like: our original long-running function now runs in a background thread via <code>ThreadPoolExecutor<\/code>, called from another async function. In Excel, it behaves just like the pure-async example \u2014 but now the work happens on a separate thread.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from pyxll import xl_func\nfrom concurrent.futures import ThreadPoolExecutor\nimport asyncio\n\n@xl_func(\"str dataset: dataframe\")\nasync def long_running_function_threaded(dataset):\n    \"\"\"Runs on the asyncio event loop, but does the actual work on a background thread.\"\"\"\n    loop = asyncio.get_running_loop()\n    with ThreadPoolExecutor() as executor:\n        return await loop.run_in_executor(executor, long_running_function, dataset)<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-rtd-with-progress-updates\"><strong>RTD with Progress Updates<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-why-rtd-helps\">Why RTD Helps<\/h3>\n\n\n\n<p>Async functions are a big improvement \u2014 they let users interrupt Excel and keep working \u2014 but they still have one drawback: there\u2019s no <em>feedback<\/em> while the function runs. The next approach fixes that by showing a <em>progress indicator<\/em> so the user can <em>see<\/em> that something\u2019s happening.<\/p>\n\n\n\n<p>Enter <strong>RTD<\/strong> (<a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/rtd.html\">Real-Time Data<\/a>) functions. RTD is usually used for streaming live data into Excel \u2014 think ticking stock prices or foreign exchange rates \u2014 but there\u2019s nothing stopping us from using it to report the progress of a long-running calculation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-generators-for-rtd\">Generators for RTD<\/h3>\n\n\n\n<p>With PyXLL, the simplest way to create an RTD function is with a <em>Python generator<\/em>. Unlike a normal function that returns once, a generator yields multiple values over time.<\/p>\n\n\n\n<p>Let\u2019s take our earlier async function and turn it into an async generator. The first step is simple: replace the <code>return<\/code> statement with <code>yield<\/code>. Then, when decorating the function with <code><a href=\"https:\/\/www.pyxll.com\/docs\/api\/udfs.html#xl-func\">@xl_func<\/a><\/code>, update the signature so PyXLL knows to treat it as an RTD function.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@xl_func(\"str dataset: rtd&lt;union&lt;dataframe, str>, auto_detach=True>\")\nasync def long_running_function_rtd_async(dataset):\n    \"\"\"Runs on the asyncio event loop.\"\"\"\n    for i in range(50):\n        await asyncio.sleep(0.05)\n\n    func = getattr(plotly.data, dataset)\n    yield func()<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-adding-progress-messages\">Adding Progress Messages<\/h3>\n\n\n\n<p>If we only yield the final value, Excel won\u2019t show anything until the function completes. So let\u2019s add some early yields \u2014 for example, a <code>\"# Working\u2026\"<\/code> message at the start, and percentage updates as the function progresses.<\/p>\n\n\n\n<p>One extra detail: our current return type is <code>rtd&lt;dataframe><\/code>, which works fine when the result is always a DataFrame. But now we\u2019re sometimes yielding strings, so we\u2019ll change it to a <strong><a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/udfs\/argtypes.html#union-types\" target=\"_blank\" rel=\"noreferrer noopener\">union type<\/a><\/strong>. That way, PyXLL knows it might get either a string or a DataFrame and will handle the conversion correctly.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@xl_func(\"str dataset: rtd&lt;union&lt;dataframe, str>>\")\nasync def long_running_function_rtd_async(dataset):\n    \"\"\"Runs on the asyncio event loop.\"\"\"\n    yield \"## Working...\"\n\n    pct = 0\n    for i in range(50):\n        await asyncio.sleep(0.05)\n        pct += 2\n        yield f\"## Running ({pct}% complete)\"\n\n    func = getattr(plotly.data, dataset)\n    yield func()<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-what-it-looks-like-in-excel\">What It Looks Like in Excel<\/h3>\n\n\n\n<p>Now, when we run our RTD-powered long-running function in Excel, we immediately see a status message. As it runs, the updates appear in real time, and when it\u2019s done, the final result replaces the progress indicator \u2014 all without blocking Excel.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1.png\"><img decoding=\"async\" width=\"1024\" height=\"550\" data-attachment-id=\"2018\" data-permalink=\"https:\/\/www.pyxll.com\/blog\/long-running-excel-functions\/image-40\/\" data-orig-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1.png\" data-orig-size=\"1291,694\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1-1024x550.png\" src=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1-1024x550.png\" alt=\"\" class=\"wp-image-2018\" srcset=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1-1024x550.png 1024w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1-300x161.png 300w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1-768x413.png 768w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/image-1.png 1291w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-restarting-rtd-functions\">Restarting RTD Functions<\/h3>\n\n\n\n<p>There\u2019s one last wrinkle: by default, RTD functions in Excel don\u2019t restart when you recalculate. If you press <strong>Ctrl + Alt + F9<\/strong> after they\u2019ve finished, you\u2019ll just see the last yielded value. That\u2019s sometimes exactly what you want (e.g., for a large dataset you don\u2019t want to reload), but other times you might want the function to start fresh.<\/p>\n\n\n\n<p>That\u2019s where PyXLL\u2019s <strong><a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/rtd.html#detaching\" target=\"_blank\" rel=\"noreferrer noopener\">auto detaching<\/a><\/strong> comes in. With <code>auto_detach<\/code> enabled in the RTD type, the function \u201cdetaches\u201d after yielding its final value, behaving like a normal Excel function again. Now, pressing <strong>Ctrl + Alt + F9<\/strong> re-runs your generator from the beginning \u2014 perfect when you want a recalculation to trigger a new run.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@xl_func(\"str dataset: rtd&lt;union&lt;dataframe, str>, auto_detach=True>\")\nasync def long_running_function_rtd_async(dataset):\n    \"\"\"Runs on the asyncio event loop.\"\"\"\n    yield \"## Working...\"\n\n    pct = 0\n    for i in range(50):\n        await asyncio.sleep(0.05)\n        pct += 2\n        yield f\"## Running ({pct}% complete)\"\n\n    func = getattr(plotly.data, dataset)\n    yield func()<\/pre>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"h-summary\"><strong>Summary<\/strong><\/h1>\n\n\n\n<p>In this walkthrough, we explored two practical ways to handle long-running Excel functions with PyXLL.<\/p>\n\n\n\n<p>First, we turned a slow function into an <strong>async function<\/strong> so it could be interrupted by the user, keeping Excel responsive. Then, we built an <strong>RTD function<\/strong> that streamed progress updates in real time \u2014 no blocking, no guesswork. Finally, we saw how PyXLL\u2019s <strong>auto detach<\/strong> feature makes RTD functions even more versatile by letting them restart cleanly when recalculated.<\/p>\n\n\n\n<p>I hope this has sparked some ideas for making your own worksheets more responsive and user-friendly when dealing with time-consuming functions.<\/p>\n\n\n\n<p>All the code from this example is linked below, and if you have any questions, feel free to reach out via the <a href=\"https:\/\/www.pyxll.com\/contact.html\" target=\"_blank\" rel=\"noreferrer noopener\">contact form<\/a> on the PyXLL website.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hit Enter, and your formula runs\u2026 but Excel is locked solid. No scrolling. No edits. Just waiting. With PyXLL, it doesn\u2019t have to be that way. You can run long Python functions without freezing Excel \u2014 and even show live progress updates while they work. Here\u2019s how. What is a long running function? Ever written<\/p>\n","protected":false},"author":1,"featured_media":2024,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[14,12,2,9],"tags":[675,6,8,678],"class_list":["post-2003","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-performance","category-python","category-pyxll","category-real-time-data","tag-async","tag-excel","tag-pyxll","tag-real-time-data"],"acf":[],"jetpack_featured_media_url":"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2025\/08\/Long-Running-Function.jpg","jetpack_shortlink":"https:\/\/wp.me\/p7l3LP-wj","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/2003","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/comments?post=2003"}],"version-history":[{"count":1,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/2003\/revisions"}],"predecessor-version":[{"id":2023,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/2003\/revisions\/2023"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media\/2024"}],"wp:attachment":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media?parent=2003"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/categories?post=2003"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/tags?post=2003"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}