keeprer. Embed ดูตัวอย่างจริง →

ฝังหน้าจอง Keeprer ลงเว็บไซต์ของคุณ

หนึ่ง <script> วางที่ไหนก็ได้บนหน้าเว็บ แล้วลูกค้าจองเวลาได้ทันทีโดยไม่ต้องออกจากเว็บคุณ คำขอทุกอันวิ่งเข้า inbox ของ Keeprer พร้อมผ่านการคัดกรองด้วย AI และร่างอีเมลตอบให้แล้ว

ไม่ต้องใช้ API key · ไม่ต้องตั้ง CORS · ไม่ต้องมี backend · ไม่มี dependency ให้ติดตั้ง

ภาพรวม

embed คือ iframe ของหน้าจองจริงของคุณ ไม่ใช่ widget ที่ยัด DOM เข้าไปในหน้าเว็บ เลือกแบบนี้เพราะสองเหตุผล:

ใครได้ประโยชน์ ธุรกิจที่มีเว็บอยู่แล้วและอยากให้คนจองจากหน้าเว็บตรงๆ — coworking space, สตูดิโอ, คลินิก, ที่ปรึกษา, ช่างภาพ, ติวเตอร์ — รวมถึงครีเอเตอร์ที่มี landing page หรือ link-in-bio ของตัวเอง

ติดตั้งใน 3 นาที

  1. เอา snippet มา — เข้า Keeprer → ShareEmbed on your site

    ต้องกรอกโดเมนก่อนถึงจะเห็นช่อง snippet เพราะรายการโดเมนว่าง = ปิดการฝังอยู่

  2. ใส่โดเมนของเว็บที่จะฝัง บรรทัดละ 1 อัน แล้วกด Save domains
    https://yoursite.com
    https://www.yoursite.com
    http://localhost:3000

    ใส่ให้ครบทุกโดเมนที่ใช้จริง www กับไม่ใส่ www นับเป็นคนละโดเมน

  3. วาง snippet ตรงที่อยากให้หน้าจองโผล่
    <script src="https://keeprer.space/embed.js" data-keeprer="your-slug"></script>

เท่านั้นจริงๆ ไม่ต้องทำกรอบหรือการ์ดมารองรับ — พื้นหลังของ embed โปร่งใส วางลงบนพื้นหลังแบบไหนก็กลืน

ทำงานยังไง

  1. embed.js อ่าน data-keeprer แล้วสร้าง <iframe> วางแทนตัวเองตรงจุดที่ script tag อยู่
  2. iframe ชี้ไปที่ /b/<slug>?embed=1 บนโดเมน Keeprer
  3. server ตอบกลับพร้อม header Content-Security-Policy: frame-ancestors … ที่สร้างจากรายการโดเมนที่คุณบันทึกไว้ เบราว์เซอร์เป็นคนบังคับใช้ ถ้าเว็บที่ฝังไม่อยู่ในรายการก็จะถูกบล็อกทันที
  4. หน้าจองเรนเดอร์แล้วส่งความสูงของตัวเองกลับมาให้หน้าเว็บแม่ผ่าน postMessage เพื่อปรับ iframe ให้พอดี ไม่มี scrollbar ซ้อน
  5. ลูกค้ากดจอง → POST เกิดขึ้นใน iframe (same-origin) → คำขอเข้า inbox ผ่าน AI screening → คุณได้อีเมลและ push แจ้งเตือน

Attribute ของ script tag

Attributeจำเป็นค่าเริ่มต้นทำอะไร
srcใช่URL ของ embed.js โดเมนใน src นี้จะถูกใช้เป็นโดเมนของ iframe ด้วย
data-keeprerใช่slug ของหน้าจอง (ส่วนท้าย URL หน้าจองของคุณ)
data-heightไม่620ความสูงเริ่มต้นเป็น px ก่อนที่ auto-resize จะส่งค่าจริงมา ตั้งให้ใกล้ของจริงจะลดการกระตุกตอนโหลด

iframe ที่สร้างขึ้นจะได้ loading="lazy" และ allow="microphone" อัตโนมัติ (อย่างหลังจำเป็นสำหรับฟีเจอร์ฝากข้อความเสียง — iframe ข้ามโดเมนจะใช้ไมค์ได้ต่อเมื่อหน้าเว็บแม่มอบสิทธิ์ให้)

Endpoint ที่เกี่ยวข้อง

MethodPathต้อง authหมายเหตุ
GET/embed.jsไม่ตัว loader
GET/b/:slug?embed=1ไม่หน้าที่ถูกฝัง ส่ง frame-ancestors ตามรายการโดเมน
POST/api/page/:slug/bookไม่ส่งคำขอจอง — เรียกได้จากใน iframe เท่านั้น (same-origin)
POST/api/page/:slug/voicemailไม่ฝากข้อความเสียง
PUT/api/me/pageใช่ตั้งรายการโดเมนด้วยฟิลด์ embed_origins: string[]
ยังไม่มี public REST API ข้ามโดเมน ทั้งระบบไม่ส่ง header Access-Control-Allow-Origin เลย /api/page/:slug/book จึงเรียกจากเซิร์ฟเวอร์หรือ JS ของคุณเองไม่ได้ — ต้องผ่าน iframe เท่านั้น นี่เป็นการออกแบบโดยตั้งใจ ไม่ใช่ของที่ยังไม่ได้ทำ: ถ้าเปิด CORS ให้ endpoint นี้ มันจะกลายเป็น open relay ที่ใครก็ยิงเข้ามาได้ทันที

กติกาการใส่โดเมน

ใส่แบบนี้ระบบเก็บเป็นหมายเหตุ
acme.comhttps://acme.comไม่ใส่ scheme = เดาเป็น https
acme.com/pricinghttps://acme.compath/query ถูกตัดทิ้ง เพราะ frame-ancestors ดูแค่โดเมน
localhost:3000http://localhost:3000loopback เดาเป็น http เพราะ dev server แทบทั้งหมดเป็น http
https://acme.com:8443https://acme.com:8443พอร์ตนับเป็นส่วนหนึ่งของโดเมน
*.acme.comถูกปฏิเสธwildcard เปิดให้ทุก subdomain รวมถึงอันที่โดนยึด ฝังหน้าคุณได้

postMessage ที่ iframe ส่งออกมา

ถ้าอยากรู้ความสูงของ embed เพื่อไปทำอย่างอื่นต่อ ดักฟังได้ — แต่ต้องตรวจ origin ทุกครั้ง

window.addEventListener('message', (e) => {
  if (e.origin !== 'https://keeprer.space') return;   // ห้ามข้ามบรรทัดนี้
  if (e.data?.type === 'keeprer:height') {
    console.log('ความสูงของ embed:', e.data.h);
  }
});

ตอนนี้มีข้อความชนิดเดียวคือ keeprer:height โดยมีแค่ตัวเลขข้ามฝั่งมา ไม่มีข้อมูลผู้จองใดๆ ฝั่ง embed.js ก็ตรวจทั้ง e.origin และ e.source ก่อนปรับความสูง

ใส่ใน React / Next.js / Vue

script tag ธรรมดาจะไม่ทำงานถ้าใส่ผ่าน JSX ตรงๆ เพราะ React ไม่รัน script ที่ inject เข้ามา วิธีที่ถูกคือสร้าง element เอง

React / Next.js (client component)

'use client';
import { useEffect, useRef } from 'react';

export function KeeprerEmbed({ slug, height = 620 }) {
  const box = useRef(null);

  useEffect(() => {
    const el = box.current;
    if (!el) return;
    const s = document.createElement('script');
    s.src = 'https://keeprer.space/embed.js';
    s.dataset.keeprer = slug;
    s.dataset.height = String(height);
    el.appendChild(s);
    // React 18 StrictMode รัน effect สองรอบตอน dev — เคลียร์ทิ้งกัน embed ซ้อน
    return () => { el.innerHTML = ''; };
  }, [slug, height]);

  return <div ref={box} />;
}

Vue 3

<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
const box = ref(null);
const props = defineProps({ slug: String });

onMounted(() => {
  const s = document.createElement('script');
  s.src = 'https://keeprer.space/embed.js';
  s.dataset.keeprer = props.slug;
  box.value.appendChild(s);
});
onUnmounted(() => { if (box.value) box.value.innerHTML = ''; });
</script>

<template><div ref="box" /></template>

WordPress / Wix / Squarespace / Webflow

ใช้บล็อกชนิด Custom HTML / Embed code แล้ววาง snippet ลงไปตรงๆ อย่าวางในบล็อกข้อความธรรมดาเพราะระบบจะ escape tag ทิ้ง

จัดวางและสไตล์

อย่าใส่ sandbox เอง ถ้าคุณสร้าง iframe เองแล้วใส่ sandbox โดยไม่มี allow-scripts allow-same-origin allow-forms หน้าจองจะไม่ทำงาน แนะนำให้ใช้ embed.js ตามปกติดีกว่า

แก้ปัญหา

กรอบว่าง + console ขึ้น “violates … frame-ancestors”

โดเมนของเว็บคุณไม่อยู่ในรายการ อ่านข้อความ error ให้ดี มันบอกทั้งโดเมนที่คุณใช้จริงและรายการที่บันทึกไว้

Framing 'https://www.acme.com/' violates the following Content Security Policy
directive: "frame-ancestors https://acme.com". The request has been blocked.

เทียบสองค่านี้ทีละตัวอักษร สาเหตุที่เจอบ่อยเรียงตามความถี่: ขาด www · http ปะทะ https · ลืมพอร์ต

ขึ้นว่า “Embedding isn’t enabled for this booking page”

รายการโดเมนยังว่าง หรือ slug ผิด ไปกรอกโดเมนที่ Share → Embed on your site แล้วกด Save

ขึ้นว่า “This booking page isn’t published”

หน้าจองยังเป็นฉบับร่าง เปิด publish ที่แท็บ Bookpage ก่อน

ไม่มีอะไรโผล่เลย ไม่มี error

เช็คว่า script tag ยังอยู่ใน DOM จริง (บาง CMS ตัด <script> ทิ้ง) และมี data-keeprer ถ้าลืม attribute นี้ console จะเตือนว่า [keeprer] missing data-keeprer

ความสูงไม่ยอมปรับ

มักเกิดจาก CSS ของเว็บคุณไปทับ เช่น iframe { height: 400px !important } ซึ่ง theme สำเร็จรูปหลายตัวมี ลองตรวจด้วย DevTools ที่ตัว iframe

ปุ่มอัดเสียงกดแล้วไม่ทำงาน

เบราว์เซอร์ให้สิทธิ์ไมค์เฉพาะหน้าเว็บที่เป็น HTTPS เท่านั้น (ยกเว้น localhost) ถ้าเว็บคุณยังเป็น http จะใช้ไม่ได้

Prompt สำหรับสั่ง AI agent

ถ้าจะให้ AI agent (Claude Code, Cursor, Copilot ฯลฯ) ติดตั้งให้ ก๊อปข้อความข้างล่างไปวางได้เลย แก้แค่ 3 ค่าที่วงเล็บเหลี่ยมไว้

ช่วยฝังหน้าจอง Keeprer ลงในเว็บนี้ให้หน่อย

ค่าที่ต้องใช้:
- slug ของหน้าจอง: [YOUR-SLUG]
- โดเมนของ Keeprer: https://keeprer.space
- หน้าที่จะให้ embed ไปโผล่: [เช่น หน้า Contact หรือ section "นัดหมาย" ในหน้าแรก]

สิ่งที่ต้องทำ:
1. สำรวจ codebase ก่อนว่าเป็น framework อะไร (React/Next/Vue/Astro/WordPress/HTML ล้วน)
   แล้วค่อยเลือกวิธีใส่ให้เข้ากับโครงเดิม
2. ใส่ snippet นี้ตรงตำแหน่งที่ระบุไว้:
   <script src="https://keeprer.space/embed.js" data-keeprer="[YOUR-SLUG]"></script>
   - ถ้าเป็น React/Vue: script tag ใน JSX/template จะไม่ทำงาน ต้องสร้าง element
     ด้วย document.createElement ใน useEffect/onMounted แล้ว appendChild
     และต้องเคลียร์ตอน unmount กัน embed ซ้อนตอน StrictMode รัน effect ซ้ำ
   - ถ้าเป็น HTML ล้วนหรือ CMS: วาง script tag ตรงๆ ในบล็อก Custom HTML
3. อย่าสร้าง wrapper/การ์ด/กรอบมาครอบ — พื้นหลังของ embed โปร่งใสอยู่แล้ว
   คุมแค่ความกว้างของ container ที่ครอบอยู่ก็พอ
4. ห้ามใส่ CSS height ทับตัว iframe เด็ดขาด เพราะความสูงมันปรับเองผ่าน postMessage
   ถ้าไปทับจะทำให้เนื้อหาโดนตัด — ถ้าเจอ CSS เดิมในโปรเจกต์ที่ตั้ง
   iframe { height: ... } แบบเหมารวม ให้ยกเว้น iframe ตัวนี้ออกมา
5. ห้ามเพิ่ม dependency ใดๆ ห้ามเรียก API ของ Keeprer จากฝั่ง server
   ไม่มี public REST API ข้ามโดเมน การจองเกิดขึ้นใน iframe เท่านั้น

เสร็จแล้วบอกผมด้วยว่า "ต้องเอาโดเมนไหนไปใส่ใน allow-list บ้าง"
โดยลิสต์ทุก origin ที่เว็บนี้เสิร์ฟจริง — ทั้ง production, staging และ dev
พร้อม scheme และพอร์ตให้ครบ (www กับไม่ใส่ www นับเป็นคนละอัน)
เพราะผมต้องเอาไปกรอกที่ Keeprer → Share → Embed on your site เอง
ถ้าไม่กรอก เบราว์เซอร์จะบล็อก iframe และขึ้นกรอบว่าง

สุดท้ายช่วยรันเว็บขึ้นมาแล้วยืนยันให้ด้วยว่า iframe โผล่จริง
ความสูงปรับเองได้ และไม่มี error ใน console

Checklist ก่อนขึ้นจริง

ยังติดอยู่? ส่งข้อความ error จาก console มาให้เต็มๆ พร้อม URL ของเว็บที่ฝัง เกือบทุกเคสจะแก้ได้จากสองอย่างนี้