loading...
Cover image for How Can I Access Environment Variables in My Static Website?

How Can I Access Environment Variables in My Static Website?

alexlsalt profile image Alex Morton Updated on ・2 min read

This post was originally published on October 9, 2020 on my blog.

Good morning and happy Friday! I've run into a bit of an issue - that I know I've solved before by putting a sort of band-aid solution on it - but I want to solve it fully now and I'm running into a bit of a wall.

Essentially, I have a static website running on simple HTML, CSS, and JavaScript. I'm currently fetching data from my podcast host API so that I can display podcast episodes without having to hardcode all of the podcast data into my own JS files.

Now, where I'm running into my issue is that I want to use an environment variable for my API access key in a .env file, but I can't use the 'require' function in my JS page because 'require' isn't available in the browser (I think that's what the issue is).

From where I stand now, I'm going to need to incorporate Node or I can rebuild the website as a React app and then install dotenv as a package and simply import it and the environment variable into my app.

I'd like to figure out the steps for adding it to my static HTML/CSS/JS site, if possible - but I'm not sure how to or even really how to phrase the question when I try to look it up.

Any guidance or insights appreciated!


P.S. Did you know I have a podcast with new episodes each Wednesday? Go listen right over here >>

The Ladies Code Collective Podcast cover art

Discussion

pic
Editor guide
Collapse
eruizdechavez profile image
Erick Ruiz de Chavez

As far as I understand you are building your site statically, and having the JS code pull the podcast data as a JSON response from some other place, BUT this other place requires an API key so you can fetch that data.

As you and @mellen mention, the only way to effectively hide this is to proxy that request on your server so you "inject" the key while keeping it hidden from the browser.

Thinking a bit "out of the box" you still have one more option, that is, pre-rendering the json file before publishing it, which is similar to what Jekyll, Hugo, Gatsby, etc. do. The new workflow would be as follows:

  • You publish a new podcast episode 👏🏻🎉.
  • A build is started (triggered by a script monitoring your RSS, a WebHook received by your build system, or you pushing a button 😉).
  • The build process fetches the new data with the hidden API key and the result is stored as a static JSON file.
  • The updated static site, including the new JSON, is published somewhere.

I have not used GitHub actions, but I am 99% sure it can be done with those, and if not, I can help you figure out how to do it using other free tools.

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez

To give a bit more context (after looking at your site), your file podcast.js would have an empty array episodes instead of the current content, and your build script would dynamically replace it with the actual content of the array fetched from the API and then publish it to your server.

Collapse
dengel29 profile image
Dan

This is totally doable via Github Actions, and Github gives you a way to have secrets or environment variables accessible via the Action. I have one that calls Airtable twice daily using the API key, pulls the json into the repo and rebuilds the website with the updated information. Totally viable and can be set to run on a schedule so you can set it and forget it!

Collapse
vonheikemen profile image
Heiker

From where I stand now, I'm going to need to incorporate Node

You're on the right track here. If you don't want to expose your API key to the browser this is the way to go. You should even fetch your podcast data in the server to eliminate the need for your api key in the front-end.

I can rebuild the website as a React app and then install dotenv as a package and simply import it and the environment variable into my app.

This is fine too, but a bit of an overkill. You don't need react for this, just a bundler. I suggest using parcel because is the most easy to use. The downside of this is that it makes the "deploy process" more complex, unless of course you just push the bundled assets directly in github (Is what I would do [but I'm not a good role model]).

Once you finish setting up parcel you should create a .env file in the same directory you have the package.json file.

APIKEY=SupaSecretStuff

Then in your html or js files you can access the variables using the process.env. prefix. Like this.

<html>
  <body>
    hello
  </body>
  <script>
    console.log(process.env.APIKEY);
  </script>
</html>
Collapse
bobrown101 profile image
Brady Brown

If your api keys or env variables are sensitive, this is not acceptable, as the compiled code that will be sent to the client will include the api keys or env bars as plain text.

Underneath the hood, webpack or parcel is doing a simple text replace

Collapse
dengel29 profile image
Dan

If you're still facing this problem, Github has a way for you to store secret or environment variables. If your goals is to hit the podcast API and save the JSON response in your project, you can use a Github action that does that: it will hit the API, gets the JSON response, put that JSON into a specific file or folder of your choosing in your project, then update your repository. I have one that does exactly that, except I hit an Airtable API for some spreadsheet info. Contact me if you want any help with it.

Collapse
alexlsalt profile image
Alex Morton Author

Thanks Dan, I'll definitely look in to this. Appreciate it!

Collapse
recursivefaults profile image
Ryan Latta

There are some good answers here but I'll give a more old-school way this used to go down.

Your code would have something like ${env.api_key} in it.

Your build pipeline searches for those and replaces it with the correct value so your build artifact has the apikey built in, but what you check in does not.

I'm not sure the javascript way to facilitate that, but I'd be willing to bet someone already wrote something to do this.

Collapse
mellen profile image
Matt Ellen

I'm not 100% sure I understand, so bare with me.

You have an API key you want to use and you want that to be present in the javascript files that you serve to end users?

Collapse
alexlsalt profile image
Alex Morton Author

Yes! That's it. But I don't want the key to be able to be seen in the project files (on GitHub for example). Does that make sense?

Collapse
mellen profile image
Matt Ellen

Yes. 👍

I'm a bit out of the loop on web dev with APIs, but if you put the key in the JS file, doesn't that mean everyone who visits your website will have access to your API key (by reading the JS file)?

If that is the case, then to keep it only on your server you'll need some server side script to make the call to the API and then put the result into the site, either as the site is rendered or via fetch, XHR or similar.

I will admit I don't know react at all, and I don't know node.js very well, but it is used as a server side script runner, so it should have the capability to do the work you need.

Collapse
gotheer profile image
gotheer

Static websites don't need ENV, but answering the question: You use Webserver ENV or system ENV.

Collapse
alexlsalt profile image
Alex Morton Author

Thanks, I'll try looking into that!

Collapse
patarapolw profile image
Pacharapol Withayasakpunt

Webpack Define Plugin.

But then, anything to goes the frontend isn't secret. You had better use a server, or a serverless functions.