How to render HTML in my theme via app created with React

valiermedia
Shopify Partner
94 23 58

Hello, I recently completed this tutorial (https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react) and then used the skills gained there to create the basic admin interface for my app. Now that I am finished with that, I would like to move to the front end development portion of the project, but I am having trouble finding a tutorial or guide that will help me access my app's data from the front end and output a list of products based on stored IDs. The output part should be easy (I have fairly extensive experience with Shopify theme development and modification), but accessing my app from the front end is a mystery to me.

I am seeing posts that mention ScriptTags...but the documentation on that is a 404 (https://shopify.dev/docs/admin-api/rest/reference/online_store/scripttag). 

 

I am assuming that the basic configuration will be:

1. Add a script tag to the header or footer of my theme
2. Add an HTML element that I can select for code injection
3. Give my script the ability to request data stored by my app
4. Give my script the ability to add HTML to the element from #2 on initialization

Where I am stuck is, how do I make a script file in my app accessible from the storefront? I am currently running a tunnel via ngrok to my local machine, but I can't just call up https://mysubdomain.ngrok.io/myscript.js. If I do, it redirects to the Shopify admin area with a 404. I imagine that this has to do with the proper means of configuring the routing in my app to allow direct access to certain public files, like myscript.js.

Once I make the script file accessible, how can I safely query data from my app or store? I realize that there are some security issues here so any direction on how to do this properly would be greatly appreciated.

I am using React and I am a PHP developer who is coming over to React for the first time outside of a course that I took which really only covered making basic UI components, so there is likely stuff regarding the routing or general server configuration that I just don't understand. Thanks in advance for your help!

Web Development | UX | Graphics
valiermedia.com

There is enough abundance to go around, so long as we look out for one another 🙂
Replies 18 (18)

Not applicable

Hi @valiermedia Here's a working link for ScriptTags:

 

https://shopify.dev/docs/admin-api/rest/reference/online-store/scripttag

 

Accessing your apps data from the storefront you have to use an app proxy. So there's no CORS issues. You can then use the script tag to make a call to your own API requesting that app data. 

 

All the best,

 

Sam 

valiermedia
Shopify Partner
94 23 58

Thanks @Anonymous! Headed down that rabbit hole now and will post a response soon.

Web Development | UX | Graphics
valiermedia.com

There is enough abundance to go around, so long as we look out for one another 🙂

valiermedia
Shopify Partner
94 23 58

I solved the majority of this challenge, and am so excited that I might just crack open an afternoon beer! Big thanks to @Anonymous for taking time to point me in the right direction. 

I wanted to post my solution below so that anyone who happens upon this thread might be able to use my process as part of their solution. Here we go...

Where I am stuck is, how do I make a script file in my app accessible from the storefront? 
I am going to use the tutorial located at https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react as a starting point for this, as many of the people who complete that tutorial are going to be left with a React app that they might not understand entirely, and that app really only is available via the admin interface. To make a script in your app available online (and thus accessible from the storefront), you need to complete the following tasks:

1. Set up an application proxy app extension
This tutorial (https://shopify.dev/tutorials/display-data-on-an-online-store-with-an-application-proxy-app-extension) does a pretty good job of explaining how to accomplish this, but it had a few sticking points that I think need to be clarified. Follow their instructions from steps 1-5 and then return here to discuss the proxy settings. Let's take a look at the (placeholder) settings that I used:


Annotation 2020-02-27 134322.jpg

So what this does, is it takes traffic from https://my-test-store.myshopify.com/apps/my-subpath and forwards it to https://reserved-subdomain.ngrok.io/test (it is a bit more complicated than that but for now that's all that matters). In the Shopify tutorial, they mention an app_path being part of the URL, which wasn't something that I needed in this case. I imagine that if I have multiple apps on a server then it comes into play, but if you are just adding to the React App tutorial, this will work.

2. I went ahead and paid for the ability to have reserved subdomains with ngrok
That way, I don't have to update the URLs in my app settings or in the proxy each time I open a new tunnel. Not a critical part of this solution, but for like 8 bucks a month...that's an easy buy.

3. Configure routing in your app so that requests for /test are handled properly
So far we have configured our proxy so that https://my-test-store.myshopify.com/apps/my-subpath is forwarded to https://reserved-subdomain.ngrok.io/test, but the app created in the tutorial is not configured to handle a request for /test. If you followed the React tutorial to the end, then you will have koa-router installed, giving you everything you need to forward /test to a script of your choice. For this example, create a directory in the root of your app named "scripts," and in that directory, create a file named testscript.js and add the following code to that file:

async function runTestRoute (ctx, next) {
	ctx.body = 'Greetings, I am test route'
};
module.exports = runTestRoute;

Then, open your server.js file in the root of your app, and add the following line* (line 15 in my app) 

  const Router = require('koa-router');
  const processPayment = require('./server/router');
+ const runTestRoute = require('./scripts/testscript');

*The first two lines are already there, but were just included to give you a frame of reference for where you can add the lines, and the + is just there to denote a new line, don't actually include the + in your code, just add const runTestRoute = require('./scripts/testscript')

Then update the same server.js file with the second line here (line 31 in my app)

  router.get('/', processPayment);
+ router.get('/test', runTestRoute);


If your app is already running, hit CTRL+C (or whatever the mac equivalent is if that's your bag) in your cmd/terminal window to shut down the app (assuming this is a development server and nobody is actually using it). Then enter npm run dev to fire it back up, and then run the following tests once it says it is ready on 3000:

Visit your ngrok URL. In this example it is https://reserved-subdomain.ngrok.io/test
You should see "Greetings, I am test route" displayed on your screen. If not, then you might have made a mistake in part 3 of this answer.

If the previous test works, visit your proxy URL. In this example that is https://my-test-store.myshopify.com/apps/my-subpath
You should see "Greetings, I am test route" displayed on your screen. If not, then you might have made a mistake in part 1 of this answer.

Note that anytime you make changes to your server.js file, you have to restart the server to view the updated app in a browser. There is supposedly a way around that via nodemon but I don't have any experience with that.

Hopefully this helps to bail someone out who gets stuck in the same spot I did. If you have any feedback or would like to suggest an edit to this answer please feel free to comment below. I am not yet an expert in Node development or Shopify development, so please feel free to make suggestions or recommendations!

Cheers

Web Development | UX | Graphics
valiermedia.com

There is enough abundance to go around, so long as we look out for one another 🙂
Not applicable

Hi @valiermedia,

 

I read your post and it's very detailed and will definitely help others! Crack that beer open because I know the feeling. One thing to point out is you will want to verify the proxy request as well. Here is a working example we use:

 

require('isomorphic-fetch');
require('dotenv').config();

var querystring = require('querystring');

const path = require('path');


const AchieveDB = require('../db');

const crypto = require('crypto');


module.exports = (function(){

	return function(request, response, next){

		const {SHOPIFY_APP_SECRET} = process.env;

		var hash, input, query, query_string, ref, ref1, ref2, signature;
		query_string = (ref = (ref1 = request.url.match(/\?(.*)/)) != null ? ref1[1] : void 0) != null ? ref : '';
		query = querystring.parse(query_string);
		signature = (ref2 = query.signature) != null ? ref2 : '';
		delete query.signature;
		input = Object.keys(query).sort().map(function(key) {
		var value;
		value = query[key];
		if (!Array.isArray(value)) {
		  value = [value];
		}
		return key + "=" + (value.join(','));
		}).join('');
		hash = crypto.createHmac('sha256', SHOPIFY_APP_SECRET).update(input).digest('hex');
		if (signature !== hash) {
		response.status(403).send("Signature verification for shopify proxy request failed");
		} else {
		next();
		}
		return null;

	}


})();

Also kudos for using Koa, it takes time to migrate and learn so you're steps ahead with Koa. 

 

All the best,

 

Sam

valiermedia
Shopify Partner
94 23 58

Thanks Sam! I don't know that any developer would survive without the wealth of knowledge that is shared in message boards across the web. Lord knows Stack Exchange has both saved my bacon a many times over the years. It also gives us the opportunity to see others provide feedback/criticisms of accepted answers, so you can go from a decent answer, to an efficient answer, to a secure and efficient answer all in one thread.

One of the worst things is when you find a post where an author asks a valid question, then replies with "Great I figured it out!" and doesn't provide a detailed response as to why it worked and how they implemented it. So I am going to try to document as many of these questions as I run into (as time allows), hopefully it helps a few people out of the weeds.

Also, this script is EXACTLY what I was just about to dive into. I will plug it into the app and let you know if I run into any issues 🙂

Cheers,
Merritt

Web Development | UX | Graphics
valiermedia.com

There is enough abundance to go around, so long as we look out for one another 🙂
Sam10201
Visitor
2 0 1

Hi @valiermedia, how did it go, did you manage to get the html rendered on the front end, I am stuck at the same stage here. 

meganspauldingc
Tourist
3 0 2

You literally just saved my life, you have no clue how much time I sunk into trying to figure this out! BLESS YOU!!!!!!!!

Sam10201
Visitor
2 0 1

Hi @meganspauldingc 

Can you please share your code here, what issues you were facing and how did you manage it?

afre92
Visitor
2 0 1

Will these work if I want to render a partial?I want to render some data from my app below the product page ? Im asking bc I see you need to set a sub path prefix and a sub path which I think It can move me away from the product page.

Thank you in advance 

Not applicable

@afre92  Sub path prefix for app proxy is the end point for your requests. You should be using AJAX so your requests are not actually redirecting the page. 

 

webdevpchoi
Shopify Partner
1 0 1

Created an account just to comment and thank you - this writeup is so good it should be included in the React + Node tutorial. You probably just saved me hours and hours of time with this. Excellent writeup sir and thank you for sharing the wealth of knowledge.

VikingGawd
Shopify Partner
5 0 1

Great write up.

 

I figured a bunch of this out before I found this which was still helpful.

 

A few other things which are not really clear and hopefully this saves someone else a whole lot of time.

 

An app proxy is very versatile.  Default will just display what is sent back and completely ignore the theme which was annoying but also can be great.

 

Things you can do with an app proxy:

- Display a completely separate page that you sent back ignoring the theme

- Display inside of the theme

- Return data in an ajax call

 

The first one most people dont actually want to do and it is what happens when you first respond.

 

The second one is what most people think about.  They want to display a page inside of the theme like you would if you created a page inside of shopify.  This keeps the themes header and footer just like a normal page would.  Its actually really easy to do.  Just add a header before sending

so for node:

```
res.setHeader('content-type', 'application/liquid')
res.send('<p>some cool page info here</p>')
```
Obviously you will have to change that information to be what you want but now you are inside of a page.  This is also liquid so you can add {% %} tags and shopify will fill it in for you.
 
Lastly pulling from ajax.  you can have the person add liquid code to the page that calls your endpoint.  Most will set it up as an include file and then have the user include that in the page.  You can send your own code like above that has a script to pull more information using liquid to fill in the blanks.  You can respond with json and have a script that uses that and updates the page.  The possibilities are endless.
 
So when you think of an App Proxy, be aware it is a lot more than the specific case you are looking for.
mark194
Shopify Partner
4 0 0

@VikingGawd, thanks so much for posting this, do you mind for a follow up question?

I am new to shopify development and would love very much to learn this you mentioned
" Display inside of the theme"

could you please explain a bit more details of what you mean 

"just add a header before sending

so for node:

```
res.setHeader('content-type''application/liquid')
res.send('<p>some cool page info here</p>')
```
Obviously you will have to change that information to be what you want but now you are inside of a page.  This is also liquid so you can add {% %} tags and shopify will fill it in for you."


basically, I want to build an app that will create an form for my customers, and I want that form to display inside anyone's theme and I want to build this form using shopify remix etc. so that I can easily integrate the data with my own database. 

I don't want to call page api since it was limited to only use html, it is not fit with shopify ploaris

thank you very much 

rickwtj
Visitor
2 0 1

Hi @valiermedia, thanks for the helpful documentation.

Was wondering how you were able to render liquid (for example a collection list of products) that renders on the storefront, matching the theme of the customer?

Not applicable

@rickwtj ,

 

The best way to do that is using a theme section that would render on a collection page. If you're doing that as a 3rd party app then you should also know that you could update theme assets using REST API also script_tag renders Liquid too. Matching the theme would require you to GET all themes than find the "main" theme which is the one published. 

 

Please clarify your overall objective since there's more than one way to render Liquid on the storefront

 

Regards,

Sam

rickwtj
Visitor
2 0 1

 @Anonymous Appreciate the reply.

To give more context, what I'm trying to do is implement a search functionality as a 3rd party public app.

This will include adding a search bar, searching an external database (that syncs with the products in the store), getting those products as a json, then rendering these products on the storefront trying to match the theme of the store (in the grid layout of the all collections page).

I'm currently doing this through an app proxy, but it might be doable without.

There are a few problems I'm facing:

1. Match the theme of the store (like you mentioned I can do a GET all themes), then insert a section that mimics product collections layout, but replace the liquid variable from ```collections.all.products``` to my filtered products list I want to render.

2. Assigning the external json to a liquid variable, then looping through this liquid variable for example ```{% paginate collections.all.products by limit %}``` to render on storefront.

Not applicable

@rickwtj  Keep the app proxy for your search requests. As far as injecting your front-end search form Shopify has a number of ways to do that which I’ve mentioned. The cleanest way is to build a new header section and let the merchant choose that section from their theme editor. Or include it as a snippet in the existing header. 

webdeveloperssp
Shopify Partner
11 0 0


I'm need help with adding HTML to strore front.

I have followed the process given in https://community.shopify.com/c/Shopify-APIs-SDKs/How-to-render-HTML-in-my-theme-via-app-created-wit...

But I'm in further stuck.

I'm testing app on dev store, and  dev store does work with only password.
and when I try URL 
https://93b8230a8ab3.ngrok.io/test
It asks me PWD and redirects to home page.
I'm following correct way?

https://prnt.sc/1273lfs

I really need help with this.

Thank you!