SEO - Generate structured data based on window.records values

I think creating a JSON via formula in Airtable then using a small script to get from the record and create a script tag with that JSON might be the best approach. It might feel scrappy but I think it’s the best option and those customisations always require some hacking :slight_smile:

My question here is why we have to do this manually, and Softr isn’t doing it for us

4 Likes

Much appreciate the help and suggestions. Let me go ahead creating the JSON in Airtable and adding this in a simple script as custom code to include it in the detail pages.

I would love to read this script :slight_smile: thanks

@aar0n Softr could get it from Airtable and put into right place similarly to SEO:Title but can’t fill in all the JSON…

Made a few attempts to insert the structured data stored from an Airtable field (SEO:JSON-LD) into the of the page. While the console.log displays the structured data correctly, it does not actually appear within the .

The line document.head.appendChild(jsonldScript); seems to be failing. Thoughts anyone?

<script>    
    document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                const recordId = getUrlParam('recordId');
                if (window.records && window.records[recordId] && window.records[recordId].record.fields['SEO:JSON-LD']) {
                    
                    const jsonldScript = document.createElement('script');
                    jsonldScript.setAttribute('type', 'application/ld+json');

                    const structuredData = window.records[recordId].record.fields['SEO:JSON-LD'];
                    
                    jsonldScript.textContent = structuredData;
                    
                    console.log(jsonldScript);
                    
                    document.head.appendChild(jsonldScript);
                    
                    clearInterval(waitForData);
                }
            }
        }, 100);

        function getUrlParam(name) {
            const url = new URL(window.location.href);
            let param;
            for(var key of url.searchParams.keys()) {
                if(key.toLowerCase() === name.toLowerCase()) {
                param = url.searchParams.get(name);
                break;
                }
            }
        
            if(!param && name.toLowerCase() === 'recordid') {
                param = getRecordIdFromPath();
            }
            return param;
        }
        
        function getRecordIdFromPath() {
            let pathName = window.location.pathname;
            if (pathName.indexOf('/r/rec') !== -1) {
                pathName = pathName.substr(pathName.indexOf('/r/rec') + 3);
                if (pathName.indexOf("/") !== -1) {
                pathName = pathName(0, pathName.indexOf('/'))
                }
                return pathName;
            }
            return undefined;
        }
    });
</script>

From the console:

1 Like

I was able to get this to work if I made the content of the SEO:JSON-LD field this:

{
  "@context": "https://schema.org",
  "@type": "Flight",
    "departureAirport": {
      "@type": "Airport",
      "name": "San Francisco Airport",
      "iataCode": "SFO"
    },
    "departureTime": "2017-03-04T20:15:00-08:00",
    "arrivalAirport": {
      "@type": "Airport",
      "name": "John F. Kennedy International Airport",
      "iataCode": "JFK"
    },
    "arrivalTime": "2017-03-05T06:30:00-05:00"
  }
}

I.e., I think you were double-enclosing the data in a <script> tag.

Interesting, thanks for trying. Double-checked that the Airtable field doesn’t already include the tags, and also tried with that exact schema.org definition, but without any luck.

Would you mind sharing your custom code?

I copied and pasted your code, so I don’t think I have anything to offer there!

Maybe it’s actually working for you? How are you going about confirming whether it’s working? What I did was to inspect the DOM of the page in the Google Chrome developer tools, and this is what I found, near the bottom of the page:

Ah, you got me - it is working as expected indeed! I had been looking for the code in the Page Source, rather than Elements within the Dev Tools. Mystery solved - much appreciate the help!

There’s (at least) one more hurdle to get over. I would not assume that the Google crawler can be counted on to wait until this JavaScript runs to add the JSON to the page, before it starts processing. I think this needs to be tested.

If you find that Google isn’t properly waiting and isn’t finding the JSON, then that’s really going to push the ball back to Softr to solve this problem, as I don’t see any way for custom code to get access to the data any sooner.

1 Like

For anyone attempting the same approach, make sure that you make proper use of the quotation marks in the Airtable formula field, e.g.:

'{
  "@context": "http://schema.org",
  "@type": "Flight",
  "provider": {
    "@type": "Airline",
    "name": "' & {airlineName} & '",
  },
  "aircraft": "' & {aircraftModel} & '"
}'

Good call. That remains to be seen indeed. I will keep an eye on it.

For what it’s worth, I didn’t have to do anything fancy with quotation marks. I used a field of type Long Text and did not turn on rich text formatting.

I suspect you’re going to be okay with the custom-code-based approach to generating the JSON, from reading the docs.

Yep, should work well without quotation marks as long as you can use a regular text field. In my case I will only generate the JSON within Airtable itself, and therefore need to use a Formula field for the values to be dynamic.

One more thing to mention about the structure of the JavaScript code above.

Right now what it’s doing is waiting until the DOMContentLoaded event, then running a block of code every 100ms to see if jQuery has been loaded, then when jQuery is loaded, it runs the main body of its code.

This happens to work, but it’s got a couple of problems that could surface in the future in really mysterious ways.

The main problem is that jQuery being loaded is not actually the right thing to wait for. First of all, I don’t believe the body of the code actually depends on jQuery being loaded at all - it doesn’t use it. Second, the thing it actually should be waiting for is the data in window.records to be available. So I think you could remove the test typeof $ != 'undefined' and move the test of window.records up to that same spot where the jQuery test was.

That would also allow you to fix the other problem, which is that today when this code runs, if the main body has an error, the clearInterval() function never gets called, and that means this little block of code will run again every 100ms as long as the page is open. This could impact responsiveness from the user’s point of view. So the solution here is to call clearInterval() at the top of the body instead of the bottom.

1 Like

Hi @dcoletta , great analysis and feedback - I modified the original script from @artur, which wasn’t necessarily intended to load JSON-LD structured data.

Appreciate the suggestions - going to experiment a bit further.

1 Like

@irestmycase @dcoletta @artur
Would anyone be able to share that updated script? I’m managing to put together the JSON in a formula field in Airtable for my purposes (job post and organization structures), but to create the script is where I struggle.

Would much appreciate any code that could be shared.

@Suzie feels like a feature, or something to create a little tutorial for users? Since getting the pages listed on Google is so crucial for everyone :slight_smile:

I would strongly agree that, if this metadata is important for SEO, Softr should generate it automatically, and there should be a way in the studio to specify which fields of a List Details block should be included. The approach in this discussion topic is a proof of concept but it’s way outside what I think of as “no-code”.

Ironically, this is all totally obsolete already, as it would work way better for the whole internet for Google to use machine learning to generate the relevant metadata automatically.

2 Likes