Skip to content

Local Development

When developing an extension with a localhost server, you’ll need to serve files over HTTPS with CORS headers. This page covers the setup.

SketchUp for Web runs on HTTPS. Browsers block “mixed content” — an HTTPS page loading resources from HTTP. So your local server needs SSL too.

We recommend mkcert for generating locally-trusted certificates. It’s simple and avoids browser security warnings.

Install mkcert, then generate a certificate:

Terminal window
mkcert -install
mkcert -key-file su-extension-key.pem -cert-file su-extension.pem localhost 127.0.0.1 ::1

This creates two files:

  • su-extension.pem — the certificate
  • su-extension-key.pem — the private key

Here’s a simple Python server that handles SSL and CORS headers. Save it as server.py:

#!/usr/bin/env python3
"""Simple HTTPS server with CORS headers for JSA extension development."""
import http.server
import ssl
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler
class CORSRequestHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET')
self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
return super(CORSRequestHandler, self).end_headers()
def serve(host, port, cert_path, privatekey_path):
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile=cert_path, keyfile=privatekey_path, password='')
server_address = (host, port)
httpd = http.server.HTTPServer(server_address, CORSRequestHandler)
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
httpd.serve_forever()
if __name__ == '__main__':
if len(sys.argv) < 4:
print(f'Usage:\n {sys.argv[0]} <port> <PEM certificate file> <private key file>')
sys.exit()
PORT = int(sys.argv[1])
CERT_FPATH = sys.argv[2]
PRIVKEY_FPATH = sys.argv[3]
serve('localhost', PORT, CERT_FPATH, PRIVKEY_FPATH)

Run it from the directory containing your extension files:

Terminal window
python3 server.py 9000 su-extension.pem su-extension-key.pem

Your extension is now available at https://localhost:9000/.

If your extension’s icons or assets aren’t loading, it’s likely a CORS issue. The Python server above adds the necessary headers, but if you’re using a different server, make sure it sends:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET

For more details, see the MDN CORS guide.