Mourning online

Me and Ngin Ngin
  1. A self-moderated guestbook that anybody could sign without social media
  2. Inexpensive or free to use


I decided to use my current setup that I’m working with on my personal website. It’s simple and straightforward — I built the site in Eleventy, stored it in Github, and deployed it to Netlify.

Guestbooks and Netlify Forms

I really wanted to avoid using third-party software for the guestbook, so I decided to try out Netlify Forms. The setup was a little complicated, but I figured it out in the end.

<form name="Guestbook" method="POST" data-netlify="true">
<li class="guest-name">
<fieldset class="line">
<input required id="name" type="text" name="name" placeholder=" "/>
<label for="name">Name*</label>
<li class="guest-email">
<fieldset class="line">
<input required id="email" type="email" name="email" placeholder=" "/>
<label for="email">Email*</label>
<li class="guest-message">
<textarea required id="message" name="message" rows="5" placeholder=" "></textarea>
<label for="message">Message*</label>
<li class="guest-photo">
<label for="photo">Add photo (optional)</label>
<input id="photo" name="file" type="file" accept="image/*" placeholder=" "/>
<li hidden>
<fieldset class="line">
<input id="bots" name="bot-field"/>
<label for="bots">Leave blank</label>
<li class="guest-captcha">
<div data-netlify-recaptcha="true"></div>
<li class="guest-submit">
<button type="submit">Send</button>
  1. You can find your Netlify form ID by going to Forms > Active forms > (your form) and copying the long string at the end of the URL.
  2. You can create a personal access token in your Applications settings.
const Cache = require('@11ty/eleventy-fetch');

* Grabs the remote data and returns back an array of objects
* @returns {Array} Empty or array of objects

module.exports = async () => {
try {
let url = "{SITE_ID}/forms/{FORM_ID}/submissions";

/* This returns a promise */
return Cache(url, {
duration: '1d', // 1 day
type: 'json',
fetchOptions: {
headers: {
'Authorization': "Bearer {ACCESS_TOKEN}"
} catch(e) {
return [];
{% for guest in guests %}
<time datetime="{{guest.created_at|htmlDateString}}">{{guest.created_at|readableDataDate}}</time>
<img src="{{}}" alt="">
{% endfor %}


The last part of putting the site together was formatting and uploading my grandmother’s memorial video. This took the longest — I had to gather over 70 years worth of old photos, organize them, scan them, and put them into a video. I did this with Apple’s scan utility, Photoshop (to clean them up a bit), and Final Cut Pro (for the video itself). You can substitute Final Cut Pro with iMovie or the video editing software of your choice.

ffmpeg -y -i -c:v libx264 -crf 30 -profile:v high -movflags +faststart -s 1280:720 video.mp4
<video width="1280" height="720" controls preload="metadata" poster="poster.jpg"> <source src="video.mp4" type="video/mp4"> </video>


I threw together this website the week before my grandmother’s funeral. It was a madwoman’s dash to the finish line, and yet I’m proud of the work I did. I’m also happy that I was able to put it together in a way that will be easy to maintain for my family — I moderate the guestbook submissions through Netlify and all they have to pay for is the domain name — $12 a year, much more inexpensive than the other monthly subscriptions that don’t include a domain name. I don’t know if anybody has needs as specific as mine, but hopefully this helps someone out there.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Gabrielle Wee

Gabrielle Wee

I’m a front-end developer working at Apple.