How can I run the React UI?

Hey folks,

I’m a blind screen reader user, and Flutter desktop accessibility still seems to have a way to go. I’ve tried both the Windows Store release and building the Flutter app from source, but it’s just not there and I’m not sure what can be done until the Flutter team makes things better.

It looks like my installation ships what may be the React UI, though. Is this included with the installation, and if so, is it possible to switch my installation to use that rather than the Flutter app?

I recognize that the React UI isn’t fully done yet. I just need to add clients and send basic invoices–is it far enough along for that?

Thanks a bunch.


I think there are some issues currently with the react app in our release builds.

However, if you are not scared of some command line work, you certainly get it working.

our repo for React is

clone the repo,
edit the .env and put in your base URL to your invoice ninja installation, and then run

npm run dev

This will spin up the react interface.

Let us know if you have any questions.

Just an update on this, we have corrected one of the issues with the current deployment of the React App. It should work much better now in v5.5.39.

We have another task to complete which is to catch any 404 errors inside the React app also

cc @ben

I receive a “401: You are not authorized to view or perform this action” error when trying switch the UI.
I first thought that I may not be logged with the admin account (id:1) but I am.


just to confirm, you are testing on v5.5.39?

No - this happens on v5.5.37 - the latest version my host provides through Softaculous.
Sorry for not providing my version right away - thought I’m close enough :wink:

Sorry if I just missed this–how do I switch UIs? As a blind screen reader user, visiting my web interface just gives me a Flutter UI with an “Enable accessibility” button that doesn’t do a whole lot. So if switching UIs is in the current UI, I probably can’t do it. I’m self-hosted though, so I have access to the database and configs.

I’ve tried running the UI from source via npm run dev, but I get lots of missing source files in my console. I can post those here if they’d be useful. One thing I’m unclear of is that there are 2 URLs in the .env file–an API URL and a whitelabel URL. What should I set the latter to for an instance hosted at



You can run this SQL query:

UPDATE accounts SET set_react_as_default_ap = 1;

Cool, got the React UI running. Unfortunately it redirects to URLs like /login which don’t work.

I tried changing the ROUTER environment variable to hash in my .env file. Should that be sufficient to change the generated URLs, or do I need another step? Or should I be fixing this in my Nginx config instead?


@david do you have any ideas?

I’ve now updated my staging version to 5.5.39 - when I click the “React” icon I get a WSOD - or better a more grey SOD. How can I switch this back?

Nevermind - I first thought I’ve set it already correctly back with
UPDATE accounts SET set_react_as_default_ap = 0
But I was looking in the wrong DB - was looking in production rather than stage where I tested this first.


hmm, i thought the most recent release would fix this, i think this may be an issue with users using Apache rather than nginx as it seems to be redirecting inappropriately.

I’ll need to get an apache environment setup.

Thanks David - I guess many shared hosting services are running on Apache.
Let me know if there are any logs I could provide for trouble shooting.

Ugh, a bit confused as someone else seems to have jumped into this.
To be clear, I’m not running Apache. This is Nginx.
I’ll see if I can edit the config. I’m using YunoHost, but using the latest InvoiceNinja as built by their CI.


If you can post your nginx config, i’ll try to help, we use nginx everywhere, and i haven’t been able to recreate the redirect issue.

Sorry for the delay. Here’s the configuration YunoHost generated for me. Note that by default it uses the Flutter app. Not sure to what extent this configuration may be broken for that too, but I’d be happy to PR any changes into the YunoHost package so this is fixed for everyone:

#sub_path_only rewrite ^/$ / permanent;

location ^~ / {

  # Path to source
  alias /var/www/invoiceninja5/public/;

  # Add headers to serve security related headers
  more_set_headers "Strict-Transport-Security: max-age=15768000; includeSubDomains; preload;";
  more_set_headers "X-Content-Type-Options: nosniff";
  more_set_headers "X-XSS-Protection: 1; mode=block";
  more_set_headers "X-Robots-Tag: none";
  more_set_headers "X-Download-Options: noopen";
  more_set_headers "X-Permitted-Cross-Domain-Policies: none";
  more_set_headers "Referrer-Policy: no-referrer";

  index index.php index.html index.htm;
    if (!-e $request_filename) {
    rewrite ^(.+)$ /index.php?q= last;

  try_files $uri $uri/ //index.php?q=;

  location ~ ^/index\.php(/.*|)$ {
    fastcgi_split_path_info ^(.+?\.php)(/.*|)$;
    set $path_info $fastcgi_path_info;
    fastcgi_pass unix:/var/run/php/php8.1-fpm-invoiceninja5.sock;

    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param REMOTE_USER $remote_user;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param SCRIPT_FILENAME $request_filename;

  # Adding the cache control header for js and css files
  location ~ \.(?:css|js|woff2?|svg|gif)$ {
    try_files $uri /index.php$request_uri;
    more_set_headers "Cache-Control: public, max-age=15778463";
    # Add headers to serve security related headers
    more_set_headers "Strict-Transport-Security: max-age=15768000";
    more_set_headers "X-Content-Type-Options: nosniff";
    more_set_headers "X-XSS-Protection: 1; mode=block";
    more_set_headers "X-Robots-Tag: none";
    more_set_headers "X-Download-Options: noopen";
    more_set_headers "X-Permitted-Cross-Domain-Policies: none";
    more_set_headers "Referrer-Policy: no-referrer";

    # Optional: Don't log access to assets
    access_log off;

  location ~* \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
    try_files $uri /var/www/invoiceninja5/public/index.php$request_uri;
    # Optional: Don't log access to other assets
    access_log off;

    # Include SSOWAT user panel.
    include conf.d/;

Wanted to bump this topic. With this configuration, I’m redirected to which 404s.

I’m wondering if a different Nginx config is needed for the React vs. Flutter UI since it’d handle lots of URLs via the React app. But I’m not sure what to change, and what URLs to allow through to the client backend.


For me the following happened:

When trying to login I briefly got a error message “invalid secret”, then the 404 error appeared.

What helped for me is removing the API_SECRET from the .env-file. Then the login did work.

Now what I wonder: is the API_SECRET still necessary if one uses 2FA?

hi everyone, we have made some changes, and have hopefully resolved this issue of switching between the react/flutters, those that are brave can trial it!

We really appreciate feedback!!