Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions cloudformation/marketing/cloudformation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,12 @@ Resources:
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1.2_2021
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 404
ResponsePagePath: /404.html
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
ResponseCode: 404
ResponsePagePath: /404.html
Comment on lines 144 to +150
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching the CloudFront CustomErrorResponses from serving /index.html to serving /404.html means unknown paths won’t load the Gatsby app anymore. If you’re relying on Gatsby createRedirect (or any client-side redirect logic) to handle legacy URLs, those legacy requests will now render the 404 page instead of redirecting unless you add explicit redirect handling at the edge (e.g., in RedirectToIndexIfRequired) or ship static redirect objects/pages for those paths.

Copilot uses AI. Check for mistakes.

RedirectToIndexIfRequired:
Type: AWS::CloudFront::Function
Expand All @@ -164,4 +167,4 @@ Resources:
}
FunctionConfig:
Comment: Redirect to index.html if required
Runtime: cloudfront-js-2.0
Runtime: cloudfront-js-2.0
1 change: 0 additions & 1 deletion marketing/gatsby-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const config: GatsbyConfig = {
{
resolve: "gatsby-plugin-robots-txt",
options: {
"host": "https://beddybytes.com",
"sitemap": "https://beddybytes.com/sitemap-index.xml",
"policy": [
{
Expand Down
22 changes: 22 additions & 0 deletions marketing/gatsby-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { GatsbyNode } from "gatsby";

const legacyRedirects = [
{
fromPath: "/2023/10/18/how-to-use-creative-ilks-baby-monitor-on-a-cellular-hotspot-a-step-by-step-guide/",
toPath: "/blog/how-to/cellular-hotspot/",
},
{
fromPath: "/2023/10/18/how-to-use-creative-ilks-baby-monitor-on-a-cellular-hotspot-a-step-by-step-guide",
toPath: "/blog/how-to/cellular-hotspot/",
},
];

export const createPages: GatsbyNode["createPages"] = async ({ actions }) => {
for (const redirect of legacyRedirects) {
actions.createRedirect({
...redirect,
isPermanent: true,
redirectInBrowser: true,
});
}
Comment on lines +14 to +21
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actions.createRedirect with redirectInBrowser: true typically only affects client-side navigation unless your hosting layer generates/serves redirect responses/pages from Gatsby’s redirect data. Given this site is deployed to S3/CloudFront (see cloudformation/marketing/cloudformation.yml), direct requests to these legacy fromPath URLs will likely still 404 unless you also implement redirects at the edge (e.g., in the CloudFront Function) or generate static redirect pages during the build.

Copilot uses AI. Check for mistakes.
};
11 changes: 8 additions & 3 deletions marketing/src/components/LandingPage/FAQSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ export const faqLibrary = {
secure: {
question: 'Is it secure?',
answer: (
<React.Fragment>
<p>
BeddyBytes uses the internet for account authentication and signalling so your devices
can establish a connection.
</p>
<p>
BeddyBytes uses WebRTC to stream video and audio directly between your devices.
We don't store any of your video on our servers, and we don't relay your media
through our servers.
Once connected, video and audio stream directly between your devices over your local
network. We do not relay or store your media on our servers.
</p>
</React.Fragment>
)
},
passwordLength: {
Expand Down
85 changes: 59 additions & 26 deletions marketing/src/components/SocialProof/Section.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,69 @@
import React from 'react'
import { Link } from 'gatsby'
import './style.scss'

const SocialProofSection: React.FunctionComponent = () => (
<section id="social-proof" className="bg-secondary text-bg-secondary py-5 ">
<div className="container">
<h2 className="text-center mb-4">
Over <span className="text-light">20,000+</span> hours monitored!
</h2>
<h3 className="text-center mb-3">
Here's what some of our users have to say
</h3>
<div className="row g-3 justify-content-center text-center mb-4 proof-metrics">
<div className="col-sm-4">
<div className="proof-metric">
<strong>20,000+</strong>
<span>hours monitored</span>
</div>
</div>
<div className="col-sm-4">
<div className="proof-metric">
<strong>30 days</strong>
<span>refund guarantee</span>
</div>
</div>
<div className="col-sm-4">
<div className="proof-metric">
<strong>Use your own</strong>
<span>phones, tablets, and laptops</span>
</div>
</div>
</div>
<h2 className="text-center mb-2">Proof from real-world use</h2>
<p className="text-center mb-4">
Families usually want three things answered before they buy:
will it work on their spare devices, is setup manageable, and does the privacy claim hold up?
Start with <Link to="/compatibility/">compatibility</Link>, then watch the demo video before you buy.
</p>
<section className="testimonials">
<blockquote className="blockquote">
BeddyBytes is very easy to use and I love that it's flexible.
I can open the parent station on my phone or laptop depending
on whether I'm studying or doing housework without lugging
around an extra screen. Knowing that images of our family
life are completely private is very reassuring too.
</blockquote>
<blockquote className="blockquote">
Great job! Your emphasis on security and sustainability by
using existing devices is commendable.
</blockquote>
<blockquote className="blockquote">
Love that it keeps things local for privacy.
</blockquote>
<blockquote className="blockquote">
The girls were tidying the garage this morning and normally I
miss out on all their daily activities but I had BeddyBytes
running on a tablet next to me during meeting and I could see
and hear them so felt more included.
</blockquote>
<figure className="blockquote">
<blockquote>
BeddyBytes is very easy to use and I love that it's flexible.
I can open the parent station on my phone or laptop depending
on whether I'm studying or doing housework without lugging
around an extra screen. Knowing that images of our family
life are completely private is very reassuring too.
</blockquote>
<figcaption>Parent using phone and laptop monitoring</figcaption>
</figure>
<figure className="blockquote">
<blockquote>
Great job! Your emphasis on security and sustainability by
using existing devices is commendable.
</blockquote>
<figcaption>Early customer focused on privacy and reuse</figcaption>
</figure>
<figure className="blockquote">
<blockquote>
Love that it keeps things local for privacy.
</blockquote>
<figcaption>Parent prioritising local-only streaming</figcaption>
</figure>
<figure className="blockquote">
<blockquote>
The girls were tidying the garage this morning and normally I
miss out on all their daily activities but I had BeddyBytes
running on a tablet next to me during meeting and I could see
and hear them so felt more included.
</blockquote>
<figcaption>Parent monitoring from a tablet during work</figcaption>
</figure>
</section>
</div>
</section>
Expand Down
32 changes: 31 additions & 1 deletion marketing/src/components/SocialProof/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
@import "../../scss/configuration";

section#social-proof {
.proof-metrics {
.proof-metric {
background-color: tint-color($secondary, 20%);
border-radius: $border-radius;
padding: 1rem;
height: 100%;

strong,
span {
display: block;
}

strong {
font-size: 1.5rem;
color: $light;
}
}
}

.testimonials {
columns: 375px 3;
column-gap: $spacer;
Expand All @@ -16,6 +35,17 @@ section#social-proof {
background-color: tint-color($secondary, 20%);
border-radius: $border-radius;
position: relative;
break-inside: avoid;

blockquote {
margin-bottom: 0.75rem;
}

figcaption {
font-size: 0.95rem;
color: tint-color($secondary, 80%);
font-style: normal;
}

&::before,
&::after {
Expand All @@ -39,4 +69,4 @@ section#social-proof {
}
}
}
}
}
7 changes: 4 additions & 3 deletions marketing/src/pages/baby-monitor-without-wifi/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const PrivateBabyMonitorPage: React.FunctionComponent = () => (
Baby monitors can be private <strong>and</strong> convenient.
</h1>
<p className="mb-5">
BeddyBytes doesn't send a single frame over the internet.
Video is streamed directly between your smartphone and laptop.
BeddyBytes uses the internet for signalling, but your video and audio
stay local between your devices on your home Wi-Fi.
</p>
<CallToAction
to="#pricing"
Expand Down Expand Up @@ -88,7 +88,8 @@ const PrivateBabyMonitorPage: React.FunctionComponent = () => (
We stream nap time directly between your smartphone and laptop using your home WiFi.
</p>
<p>
An internet connection is required to establish the connection between devices. But no video is sent over the internet.
An internet connection is required for account authentication and signalling so your devices can find each other.
Once connected, no video or audio is sent through our servers.
</p>
<section>
<h3>Features</h3>
Expand Down
33 changes: 33 additions & 0 deletions marketing/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ const IndexPage: React.FunctionComponent<PageProps> = () => {
minutes with no cloud video relay, no cloud recording, and no
cloud storage.
</p>
<p className="mb-4">
Want to check your spare devices before you pay? Start with the
compatibility checker and setup video.
</p>
<div className="d-flex flex-column flex-sm-row gap-2 justify-content-lg-start justify-content-center mb-4">
<Link to="/compatibility/" className="btn btn-outline-light btn-lg">
Check compatibility
</Link>
<Link to="#demo" className="btn btn-light btn-lg">
Watch setup video
</Link>
</div>
</React.Fragment>
<StaticImage
src="../images/BabyStationRunning.jpg"
Expand Down Expand Up @@ -57,6 +69,27 @@ const IndexPage: React.FunctionComponent<PageProps> = () => {
transformOptions={{ fit: "contain" }}
/>
</DefaultHowToSection>
<section className="py-4 bg-body-secondary">
<div className="container">
<div className="row g-3 align-items-center">
<div className="col-lg-8">
<h2 className="h4 mb-2">Reduce the obvious buyer risk before purchase</h2>
<p className="mb-0">
Check whether your phones, tablets, and laptops support the browser features BeddyBytes
needs, then compare that against the 5-minute setup video before you head to pricing.
</p>
</div>
<div className="col-lg-4 d-grid gap-2 d-sm-flex justify-content-lg-end">
<Link to="/compatibility/" className="btn btn-primary">
Check compatibility
</Link>
<Link to="#demo" className="btn btn-outline-primary">
See it in action
</Link>
</div>
</div>
</div>
</section>
<Features>
<h2>Key features for private baby monitoring</h2>
</Features>
Expand Down
Loading