Lite JavaScript SDK for the FamilySearch API. This SDK is designed for use in a web browser and uses XMLHttpRequest.
Getting Started:
-
📖 Demo Application - Interactive demo showing authentication, tree data, and sources
-
🔍 API Reference - Explore all FamilySearch API endpoints
Download or include the SDK directly from the CDN
<script src="https://unpkg.com/fs-js-lite@latest/dist/FamilySearch.min.js"></script>Or install from npm
npm install --save fs-js-lite
- Browser: All modern browsers (Chrome, Firefox, Safari, Edge)
- Node.js: Version 20.0.0 or higher (for server-side usage and development)
The SDK includes a UMD wrapper to support being loaded in AMD environments (RequireJS) and Node as well as being loaded as a browser global.
fs.get('/platform/users/current', function(error, response){
if(error){
console.error(error);
} else {
console.log(response.data);
}
});// Create a client instance. All available options are shown here for the sake
// of documentation though you normally won't specify all of them.
var fs = new FamilySearch({
// Specify the FamilySearch reference environment that will be used. Options
// are: 'production', 'beta', and 'integration'. Defaults to 'integration'.
environment: 'production',
// App keys are obtained by registering you app in the FamilySearch developer's center.
// https://familysearch.org/developers/docs/guides/gs1-register-app
appKey: 'ahfud9Adjfia',
// Required when using OAuth.
// https://familysearch.org/developers/docs/guides/authentication
redirectUri: 'https://example.com/fs-redirect',
// Optionally initialize the client with an access token. This is useful when
// authentication is handled server-side.
accessToken: 'myaccesstoken',
// Save the access token in a cookie and load if from a cookie so that the
// session isn't lost when the page reloads or changes. Defaults to false.
// Use the `tokenCookie` option to change the name of the cookie.
saveAccessToken: true,
// Name of the cookie where the access token will be stored when `saveAccessToken`
// is set to `true`. Defaults to 'FS_AUTH_TOKEN'.
tokenCookie: 'FS_AUTH_TOKEN',
// Path value of the access token cookie.
// Defaults to '/' (available to entire domain). Recommended for most applications.
tokenCookiePath: '/',
// Set the Secure flag on cookies (HTTPS only). Defaults to true.
// Only set to false for local development over HTTP.
// See SECURITY.md for security best practices.
secureCookies: true,
// SameSite cookie attribute for CSRF protection. Defaults to 'strict'.
// Options: 'strict' (most secure), 'lax', or 'none' (requires secure: true)
// See SECURITY.md for details on when to use each option.
sameSite: 'strict',
// Maximum number of times that a throttled request will be retried. Defaults to 10.
maxThrottledRetries: 10,
// List of pending modifications that should be activated.
pendingModifications: ['consolidate-redundant-resources', 'another-pending-mod'],
// Optional settings that enforces a minimum time in milliseconds (ms) between
// requests. This is useful for smoothing out bursts of requests and being nice
// to the API servers. When this parameter isn't set (which is the default)
// then all requests are immediately sent.
requestInterval: 1000
});You can also change these options later via config(). It accepts the same options.
fs.config({
appKey: 'mynewappkey'
})Starting with v3.0.0, fs-js-lite sets secure cookie defaults to protect against common web vulnerabilities:
secure: true- Cookies only sent over HTTPS (prevents network eavesdropping)sameSite: 'strict'- Cookies not sent with cross-site requests (CSRF protection)path: '/'- Cookies available across your entire domain
Production (HTTPS) - No changes needed:
var fs = new FamilySearch({
appKey: 'your-app-key',
saveAccessToken: true
// Secure defaults automatically applied
});Local Development (HTTP) - Disable secure cookies:
var fs = new FamilySearch({
appKey: 'your-app-key',
saveAccessToken: true,
secureCookies: false // Required for http://localhost
});See SECURITY.md for complete security documentation and best practices.
We recommend reading the FamilySearch Authentication Guide before deciding which authentication methods are best for you.
oauthRedirectURL([state]) - Obtain the URL of the login screen on familysearch.org
that the user should be redirected to for initiating authentication via OAuth 2.
This method will automatically assemble the URL with the proper query parameters
(the app key and redirect URI that were specified when the sdk client was created).
oauthRedirect([state]) - Begin OAuth 2 by automatically redirecting the user to the
login screen on familysearch.org. This only works in the browser as a shortcut
for window.location.href = fs.oauthRedirectURL();.
oauthToken(code, [verifier,] callback) - In the second step of OAuth 2, exchange the code
for an access token. The access token will be saved if that behavior is enabled.
Optionally accepts a PKCE verifier parameter for enhanced security (recommended).
The callback is a normal request callback that recieves error and response
parameters.
PKCE (Proof Key for Code Exchange) is an OAuth 2.0 security extension that protects against authorization code interception attacks. We recommend using PKCE for all OAuth flows, especially in public clients (browser apps, mobile apps).
generateCodeVerifier() - Generate a cryptographically secure code verifier string for PKCE flow.
generateCodeChallenge(verifier) - Compute the SHA-256 code challenge from a verifier.
PKCE Flow Example:
// Step 1: Generate PKCE parameters
var verifier = fs.generateCodeVerifier();
var challenge = fs.generateCodeChallenge(verifier);
// Store verifier for later (sessionStorage in browser, secure storage in mobile)
sessionStorage.setItem('pkce_verifier', verifier);
// Step 2: Start OAuth with PKCE challenge
var oauthUrl = fs.oauthRedirectURL({
state: 'my-state-value',
codeChallenge: challenge
});
window.location.href = oauthUrl;
// Step 3: Exchange code with verifier (after OAuth redirect)
var code = getCodeFromURL(); // Extract from query parameter
var verifier = sessionStorage.getItem('pkce_verifier');
fs.oauthToken(code, verifier, function(error, response) {
if (error) {
console.error('Authentication failed:', error);
} else {
console.log('Authenticated! Token:', fs.getAccessToken());
}
});Testing PKCE: Use the included test-pkce-browser.html tool to verify PKCE works with your app key. See TEST-PKCE-FLOW.md for details.
oauthUnauthenticatedToken(ipAddress, callback) - Request an
unauthenticated access token.
The access token will be saved if that behavior is enabled. ipAddress is the
IP address of the user. The callback is a normal request callback that recieves
error and response parameters.
oauthResponse([state,] callback) - When handling the OAuth 2 response in the browser,
call this method which is automatically extract the code from the query
parameter and call oauthToken() for you. The method will return false if no
code was found in the query paremeter or when the optional state parameter is
given and it doesn't match the state paremeter in the query. true is returned
when a code was found and a request was sent to exchange the code for an access
token. In that case you still must use a callback to check the response of that
request and verify whether an access token was received.
oauthPassword(username, password, callback) - Use the OAuth password flow.
Access tokens will be automatically saved in a cookie if that behavior is
enabled. The OAuth password flow is disabled by default for app keys. Contact
Developer Support to inquire about it being enabled for your app key. Typically
only mobile and desktop apps are granted permission.
setAccessToken(accessToken) - Set the access token. This will also save it in
a cookie if that behavior is enabled.
getAccessToken() - Get the access token if one is set. This does not send a
request to the API to initiate authentication, it just returns what is currently
stored in the sdk client's properties.
deleteAccessToken() - Delete the access token. This doesn't actually invalidate
the access token it just removes it from the sdk client.
Authentication can be completely handled in the browser. First you would call
oauthRedirect() to send the user to the login screen on familysearch.org. Then
when the user returns to your app you would call oauthResponse() to complete
authentication. You would also likely want to set the saveAccessToken to true
when instantiating the SDK.
When handling authentication on the server, you first redirect the user to the URL
returned by oauthRedirectURL(). Then when the user returns to your app you
will retrieve the code from the query paremeters and call oauthToken() to
complete authentication. When authentication is finished you would typically
save the access token in a session so that the user remains authenticated
between page loads. See the node sample app
for an example of how this can be done with Express.
You can also use a mixed approach to authentication by beginning in the browser with the redirect to familysearch.org and handling the response on the server.
// GET
fs.get('/platform/users/current', function(error, response){ });
// POST
fs.post('/platform/tree/persons', {
body: { persons: [ personData ] }
}, function(error, response){ });
// HEAD
fs.head('/platform/tree/persons/PPPP-PPP', function(error, response){ });
// DELETE
fs.delete('/platform/tree/persons/PPPP-PPP', function(error, response){ });
// The SDK defaults the Accept and Content-Type headers to application/x-fs-v1+json
// for all /platform/ URLs. But that doesn't work for some endpoints which use
// the atom data format so you'll need to set the headers yourself.
fs.get('/platform/tree/persons/PPPP-PPP/matches?collection=records', {
headers: {
Accept: 'application/x-gedcomx-atom+json'
}
}, function(error, response){ });
// Underneath the covers, `get()`, `post()`, `head()`, and `delete()` call the
// `request()` method which has the same method signature.
fs.request('/platform/tree/persons/PPPP-PPP', {
method: 'POST',
body: { persons: [ personData ] }
}, function(error, response){ });
// The options object is optional. When options are not include, the SDK will
// automatically detect that the callback is the second parameter.
// The `method` defaults to 'GET'.
fs.request('/platform/tree/persons/PPPP-PPP', function(error, response){ });Request options:
method- The HTTP method. Supported methods areGET,POST,HEAD, andDELETE. Defaults toGET.headers- HTTP request headers in an object where header names are keys. The SDK will defaultAcceptandContent-Typetoapplication/x-fs-v1+json. Usually that's what you want but some endpoints requireapplication/x-gedcomx-atom+jsonso you'll have to specifically set that.body- The request body. Only valid when themethodisPOST. The body may be a string or an object.
Any other options you include in the request will be made available to
middleware at request.options. This allows you to pass request options to
custom middleware.
Responses are objects with the following properties and methods:
statusCode- IntegerstatusText- Stringheaders- Map of the response headers. Header names are lowercased.body- Response body text, if it existsdata- Object; only exists if thebodyis parsable JSONoriginalUrl- StringeffectiveUrl- Will be different fromoriginalUrlwhen the request is redirectedrequestMethod- HTTP method used on the requestrequestHeaders- HTTP headers set on the requestredirected- Boolean specifying whether the request was redirectedthrottled- Boolean specifying whether the request was throttledretries- Integer. Number of times the request was retried. Requests are only retried when they are throttled.
There are two types of errors: network errors and HTTP errors.
For HTTP errors the developer needs access to the response object. The SDK makes no attempt to interpret HTTP status codes and enable built-in error handling behaviors. It is the developer's job to interpret and respond to HTTP errors.
Network errors are returned as the first argument to response callbacks.
fs.get('/platform/tree/persons/PPPP-PPP', function(error, response){
if(error){
alert('Network error');
}
else if(response.statusCode >= 500){
alert('Server error');
}
else if(response.statusCode >= 400){
alert('Bad request');
}
else {
alert('Looking good');
}
});Redirects are not automatically followed by the SDK. Usually you'll want to automatically follow the redirects but in some cases such as fetching portraits you just want to know what the redirect URL is but not actually follow it. Thus you must specify via a request option when you want the SDK to follow the redirect.
client.get('/platform/tree/current-person', {
followRedirect: true
});The SDK will automatically retry throttled requests and obey the throttling
headers which tell how long to wait until retrying the request. Response objects
include the retries property which is an integer specifying how many times the
request was throttled and a throttled property which is true when the request
has been throttled.
The SDK allows for customizing the request and response processing via middleware. Middleware can be used to support caching, logging, and other features.
// Add request middleware to log all requests
fs.addRequestMiddlware(function(client, request, next){
console.log(request.method + ' ' + request.url);
next();
});Request middleware is applied to every request the API makes. Request middleware
is a function with the signature (client, request, next).
clientis the instance of the FamilySearch sdk that the request is associated with.requestis an object that has {url, method, headers, body}.nextis a method that must be called when the middleware is done. Its signature isfunction(error, response). In most cases nothing will be returned. When an error is returned the middleware chain will be canceled and the error will be returned to the request callback. A response may be returned by the middleware to enable caching. In this case the response is immediately returned.
Request middleware is applied in the order that it was added. The SDK sets up some request middleware by default.
// Add response middleware to log all responses
fs.addResponseMiddlware(function(client, request, response, next){
console.log(response.originalUrl + ' ' + response.statusText);
next();
});Response middleware is applied to every response received from the API. Response
middleware is a function with the signature (client, request, response, next).
clientis the instance of the FamilySearch sdk that the request is associated- with.
requestis an object that has {url, method, headers, body}.responseis a response object.nextis a method that must be called when the middleware is done. Its signature isfunction(error, cancel). Whencancelhas any truthy value the response middleware chain is canceled but unlike request middleware the request callback is not called. Cancelling is done when a new request must be issued, such as middleware that handles redirects or throttling. In this case the subsequent request will have it's own middleware chain.
Response middleware is applied in the order that it was added. The SDK sets up some response middleware by default.
Some request and response middleware is configured by default for processing request bodies, handling throttling, and other default functionality.
At the moment there is no official way to modify the default middleware. Visit issue 6 to voice your support for this functionality and express your opinion on how it should be done.
If you would prefer having response bodies deserialized with an object model instead of traversing plain JSON objects then you can register response middleware to use gedcomx-fs-js.
// First you need to setup gedcomx-js and gedcomx-fs-js. See those libraries
// for instructions. Here we will assume they are available in the current
// scope as `GedcomX`.
// Then we register the middleware. When a response has a body, the body is
// deserialized into an object model provided by gedcomx-js and made available
// on the request via the `gedcomx` attribute.
fs.addResponseMiddleware(function(client, request, response, next){
if(response.data){
if(response.data.entries){
response.gedcomx = GedcomX.AtomFeed(response.data);
}
else if(response.data.access_token){
response.gedcomx = GedcomX.OAuth2(response.data);
}
else if(response.data.errors) {
response.gedcomx = GedcomX.Errors(response.data);
}
else {
response.gedcomx = GedcomX(response.data);
}
}
next();
});Version 3.0.0 introduces secure cookie defaults that may affect your application.
Breaking Changes:
-
Secure cookies now default to
true- Cookies require HTTPS by default- ✅ Production apps on HTTPS: No changes needed!
⚠️ Local development on HTTP: AddsecureCookies: false
-
Cookie path now defaults to
'/'instead of current path- This is an improvement for most apps - tokens now available across entire domain
-
New
sameSite: 'strict'default - CSRF protection enabled by default- Most apps benefit from this security improvement
- Set to
'lax'if you need cross-site top-level navigation
Quick Migration:
// Production (HTTPS) - No changes needed!
var fs = new FamilySearch({
appKey: 'your-app-key',
saveAccessToken: true
// Secure defaults applied automatically
});
// Local Development (HTTP) - Add secureCookies: false
var fs = new FamilySearch({
appKey: 'your-app-key',
saveAccessToken: true,
secureCookies: false // Required for http://localhost
});See MIGRATION-v3.md for the complete migration guide with detailed scenarios, troubleshooting, and rollback instructions.
Breaking changes:
- The
getHeader()andgetAllHeaders()response methods were replaced with theheadersobject. saveAccessTokennow defaults tofalseinstead oftrue.- The signature of response callbacks changed from
function(response)tofunction(error, response). - In v1 response middleware was called even when a network error occurred. In v2 the response middleware is only called when a response is actually recieved.
- Redirects are not automatically followed. Use the
followRedirect: truerequest option to have the SDK automatically follow a redirect response.
The SDK includes a comprehensive test suite covering both Node.js and browser environments.
# Run all tests
npm test
# Run tests with coverage report
npm run coverage
# Run only Node.js tests
npm run test:node
# Run only browser environment tests
npm run test:browserNote: Tests work out-of-the-box with no setup required. They use pre-recorded API responses (fixtures) and don't need credentials. The test suite automatically uses sensible defaults from test/sandbox.example.js. You only need to configure credentials if you want to re-record fixtures (see below).
The test suite uses:
- Mocha - Test framework
- Chai - Assertion library
- Nock - HTTP mocking for Node.js tests
- jsdom - Browser environment simulation
Tests are located in the test/ directory:
test/node.js- Node.js environment teststest/browser.js- Browser environment teststest/pkce.js- PKCE (OAuth 2.0 security extension) teststest/responses/- Pre-recorded API response fixtures
Test fixtures in test/responses/ are pre-recorded API responses. To re-record them (for example, after API changes):
Prerequisites:
-
Create
test/sandbox.jsfrom the template:cp test/sandbox.example.js test/sandbox.js
-
Get a valid FamilySearch access token:
- Go to https://beta.familysearch.org/platform
- Click the "Authenticate" button
- Click the clipboard icon next to the access token to copy it
-
Add the token to
test/sandbox.js:module.exports = { appkey: 'YOUR_APP_KEY', accessToken: 'YOUR_ACCESS_TOKEN_HERE' };
Or use an environment variable:
export FS_ACCESS_TOKEN='your-token-here'
Re-record fixtures:
# Re-record all fixtures (requires valid access token)
npm run test:record
# Re-record in "wild" mode (allows unmocked requests)
npm run test:wildNote: Access tokens expire after ~1 hour, so get a fresh token each time you re-record fixtures.