SDKs Customizations

Customization

With the goal of making the capture experience closer to your visual identity, it is possible to customize some components in the layout of the Instruction and Camera screens.

Customization Methods

Currently, there are two ways to customize the SDK:

  • Using FortfaceCustomizer, through the entry function FortfaceSDK.setCustomizer(customizer).
  • Using a JSON file, through the entry function FortfaceSDK.setCustomization("file_name").

Both approaches currently coexist, but FortfaceCustomizer will be deprecated in the future.

For new integrations, we recommend using JSON-based customization.

Instruction Screen

Instruction Screen

1-Screen

a.Visibility on/off

customizer.instructionScreen = true

2-Back Button (X)

a.Icon image

customizer.cancelButton.image = *X image

b.Visibility on/off

customizer.cancelButtonEnable = true

c.Position

customizer.cancelPosition = CancelPosition.Left

3-Texts

a.Title

customizer.instructionTextFont.header = poppins_bold customizer.instructionMessage.setInstructionHeader("Important tips for your face photo!") customizer.instructionMessageColor.setHeaderTextColor("#332D41")

b.Items

customizer.instructionTextFont.Int = poppins_regular customizer.instructionMessage.setInstructionNoItems("Keep your face visible and remove items like glasses and hats") customizer.instructionMessage.setInstructionPlace("Find a well-lit location") customizer.instructionMessage.setInstructionExpression("Keep your expression neutral") customizer.instructionMessage.setInstructionPosition("Position your phone at face level") customizer.instructionMessageColor.setMessageTextColor("#332D41")

4-Icons

a.Icon color

customizer.instructionIcon.setColor("#00A594")

b.Icon background color

customizer.instructionIcon.setBackgroundColor("#F1F1F1")

5-Continue Button

a.Button color

customizer.InstructionButton.setColor("#00A594")

b.Text color

customizer.InstructionButton.setTextColor("#FFFFFFFF")

c.Text

customizer.instructionButton.setText("Continue")

d.Text font

customizer.instructionButton.font = R.font.poppins_font_family

e.Rounded border

customizer.InstructionButton.radius = 10

6-Screen background

a.Background color

customizer.instructionBackground.setColor("#FAFAFA")

Camera Screen - Biometric Capture

Camera Screen

1-Timeout

a.Time

customizer.cameraTimeout = 30 customizer.cameraMinStabilizationTime = 2 customizer.cameraMaxStabilizationTime = 3 customizer.brightnessValidationTimeout = 10

b.Global session timeout (Android only)

customizer.setSdkTimeout(300)

cameraTimeout and sdkTimeout are independent

Before configuring both, see Android timeouts.

2-Back Button (X)

a.Icon image

customizer.cancelButton.image = *X image

b.Visibility on/off

customizer.cancelButtonEnable = true

c.Position

customizer.cancelPosition = CancelPosition.Left

3-Feedback messages

a.Font

customizer.cameraFont.cameraMessageFont = poppins_semibold

b.Texts

Deprecated properties

customizer.cameraMessage.setStartMessage("Frame your face inside the oval shape")
customizer.cameraMessage.setFaceNoCenter("Center your face")

customizer.cameraMessage.setFacePositioned("Wait for validation, try not to move")
customizer.cameraMessage.setNoFace("Position your face in the indicated area")
customizer.cameraMessage.setFaceFar("Move your face closer")
customizer.cameraMessage.setFaceNear("Move your face away")
customizer.cameraMessage.setFaceCenterLeft("Move the camera\nto the left")
customizer.cameraMessage.setFaceCenterRight("Move the camera\nto the right")
customizer.cameraMessage.setFaceCenterUp("Move the camera\nto the top")
customizer.cameraMessage.setFaceCenterDown("Move the camera\nto the bottom")
customizer.cameraMessage.setFacePitchIsUp("Lower your face")
customizer.cameraMessage.setFacePitchIsDown("Raise your face")
customizer.cameraMessage.setNoFaceYaw("Look forward")
customizer.cameraMessage.setNoFaceRoll("Keep your head straight")
customizer.cameraMessage.setFaceRollLeft("Tilt your head to the left")
customizer.cameraMessage.setFaceRollRight("Tilt your head to the right")
customizer.cameraMessage.setFaceBrightnessLow("Improve lighting")
customizer.cameraMessage.setFaceBrightnessHigh("Reduce light on your face")

Accessibility

The property setNoFaceRoll is replaced by the properties setFaceRollLeft and setFaceRollRight for users with active screen readers.

c.Color

customizer.cameraColor.setMessageTextColor("#263238")

4-Status

Deprecated properties

customizer.cameraColor.setNeutralColor("#CDCDCD")

a.Alert

customizer.cameraColor.setAlertColor("#FF9902")

b.Success

customizer.cameraColor.setSuccessColor("#5FC213")

c.Brightness

customizer.cameraColor.setBrightnessAlertColor("#24B8C2")

5-Message frames

a.Visibility on/off

customizer.cameraFrameText.visible = true

6-Success status loading

a.Color

customizer.cameraLoading.setCameraLoadingColor("#5FC213")

7-Screen background

a.Color

customizer.cameraBackground.setColor(R.color.new_color_1)

a.Image

customizer.cameraLogo.logo = R.drawable.ic_small_logo

9-Modal Mode

a.Modal mode activation

customizer.screenMode = ScreenMode.Modal

b.Background

customizer.modalBackground.setOverlayColor("#000000") customizer.modalBackground.overlayOpacity = 0.2f

c.Orientation

customizer.screenOrientation = ScreenOrientation.Automatic

10-Brightness Icon

a.Image

customizer.cameraIcon.setHighBrightnessIcon(R.drawable.ic_brightness_high) customizer.cameraIcon.setLowBrightnessIcon(R.drawable.ic_brightness_low)

b.Color

customizer.cameraIcon.setBackgroundColor("#F1F1F1")

Camera Screen - Document Capture

Camera Screen - Document Capture

1-Maximum timeout

customizer.cameraTimeout = 60 customizer.documentAutomaticCaptureTimeout = 20

2-Frame status

a.Neutral

customizer.document.setFrameNeutralColor("#F44336")

b.Success

customizer.document.setFrameSuccessColor("#9C27B0")

3-Success status loading

a.Background color

customizer.document.setLoadingBackgroundColor("#F44336")

b.Stroke color

customizer.document.setLoadingStrokeColor("#9C27B0")

4-Back button (X)

a.Icon image

customizer.cancelButton.image = *X image

b.Visibility on/off

customizer.cancelButtonEnable = true

c.Position

customizer.cancelPosition = CancelPosition.Left

5-Positioning text

a.Font

customizer.cameraFont.cameraMessageFont = R.font.poppins_semibold

b.Texts

customizer.docCameraMessage.setStartMessage("Encaixe seu documento\nna marcação")
customizer.docCameraMessage.setDocPositionedMessage("Mantenha seu celular parado")
customizer.docCameraMessage.setDocOutOfFrameMessage("Posicione seu documento\ndentro da área indicada")
customizer.docCameraMessage.setDocMisalignedMessage("Deixe seu documento reto")
customizer.docCameraMessage.setDocNotFoundMessage("Nenhum documento encontrado,\ntente posicionar novamente")
customizer.docCameraMessage.setDocFarMessage("Aproxime a câmera\ndo seu documento")
customizer.docCameraMessage.setDocNearMessage("Afaste a câmera\ndo seu documento")
customizer.docCameraMessage.setDocCapturedMessage("Não se mova")
customizer.docCameraMessage.setWrongFaceMessage("Mostre o verso do documento")
customizer.docCameraMessage.setDocTapToFocusMessage("Toque na tela para focar")

c. Colors

customizer.docCameraMessage.setFeedbackMessageColor("#FFFFFF")

6-Capture button

a.Background color

customizer.documentCameraButton.setColor("#00A594")

b.Text color

customizer.documentCameraButton.setTextColor(R.color.white) customizer.documentCameraButton.setPressedColor("#00A594")

c.Text font

customizer.documentCameraButton.font = R.font.poppins_regular

d.Text

customizer.docCameraMessage.setDocManualCaptureButtonMessage("Tirar foto")

7-Confirmation text

a.Font

customizer.cameraFont.cameraMessageFont = R.font.poppins_semibold

b.Text

customizer.docCameraMessage.setDocPreviewMessage("Seu documento está\nnítido e legível?")

c. Colors

customizer.docCameraMessage.setDocPreviewMessageTextColor("#FFFFFF")

8-Confirmation buttons

a.Font

customizer.documentPreviewButtons.font = R.font.poppins_regular

b.Text color

customizer.documentPreviewButtons.setAcceptTextColor(R.color.white) customizer.documentPreviewButtons.setCancelTextColor(R.color.white)

c.Background color

customizer.documentPreviewButtons.setAcceptColor("#367C14") customizer.documentPreviewButtons.setPressedColor("#26570E") customizer.documentPreviewButtons.setCancelColor("#B3261E") customizer.documentPreviewButtons.setPressedCancelColor("#B3261E")

d.Text

customizer.docCameraMessage.setDocPreviewConfirmCapture("Sim, enviar")
customizer.docCameraMessage.setDocPreviewRetryCapture("Tirar nova foto")

Document Upload

Document Upload

1 - Back button (X)

a.Image

customizer.cancelButton.image = *X image

b.Visibility on/off

customizer.cancelButtonEnable = true

c.Position

customizer.cancelPosition = CancelPosition.Left

2 - Texts

a. Messages

customizer.uploadDocMessage.setUploadDocTitle("Confirme seu documento")
customizer.uploadDocMessage.setUploadDocSubtitle("Sua imagem deve estar com os dados legíveis e em boa qualidade.")

b. Colors

customizer.uploadDocMessage.setUploadDocTitleTextColor("#000000") customizer.uploadDocMessage.setUploadDocSubtitleTextColor("#AAAAAA")

3 - Confirmation buttons

a. Confirmation

customizer.uploadDocMessage.setUploadDocPreviewContinue("Enviar documento")
customizer.uploadDocMessage.setUploadDocPreviewContinueButtonColor("#00A594")
customizer.uploadDocMessage.setUploadDocPreviewContinueButtonTextColor("#FFFFFF")
customizer.uploadDocMessage.setUploadDocWaitMessage("Aguarde")
customizer.uploadDocMessage.setUploadDocPreviewRetryTextColor("#00A594")

b. Reenvio

customizer.uploadDocMessage.setUploadDocPreviewRetry("Carregar novamente")

4 - Background color

a. Color

customizer.uploadDoc.setBackgroundColor("#FFFFFF")

How does it work?

Each variable has its default value.

  • If you assign a new value according to the variable type, the new value will be rendered;
  • If no new value is assigned, the initial default will be rendered.
  • In the case of the capture screen logo, if no image is initialized, nothing will appear

Understanding the code snippet

First, initialize the FortfaceCustomizer class:

val customizer = FortfaceCustomizer()

Then, change the desired parameters:

customizer.cameraColor.setNeutralColor(R.color.new_color_1) customizer.cameraColor.setSuccessColor("#9C27B0") customizer.cameraMessage.setFaceNear(R.string.text_1) customizer.cameraMessage.setStartMessage("Let's start")

Then, override the default customizer:

FortfaceSDK.customizer=customizer

Reminder

All specific items, such as: icons, images, font family, etc., must be imported into the Assets folder of your app.

Android timeouts

The Android SDK has two independent timeouts with different scopes. Setting them to equal or close values makes them compete to end the session.

PropertyScopeDefault valueLimits
cameraTimeoutCamera/capture screen. Starts counting when the capture begins.30 secondsMinimum of 20 seconds. Lower values throw IllegalArgumentException.
sdkTimeoutThe whole SDK session. Starts counting when the SDK screen opens and applies to any step of the flow, including the instruction screen.540 secondsMaximum of 600 seconds. Higher values are clamped to 600, with no error.
sdkTimeout is Android only

On iOS there is only cameraTimeout. There is no equivalent global session timeout.

How to configure

cameraTimeout is a FortfaceCustomizer property. sdkTimeout is set through the setSdkTimeout function and read through getSdkTimeout; it is not accepted in JSON customization.

customizer.cameraTimeout = 120 customizer.setSdkTimeout(300)

What each timeout delivers when it fires

Both end the session with Action.Timeout, but the payload differs:

  • cameraTimeout: the session ends with getData() populated, containing key and data.
  • sdkTimeout: the session ends with getData() equal to null. There is no metrics payload to forward to the backend.

Competition between the two timeouts

sdkTimeout is not limited to the instruction screen: it counts from the moment the SDK opens and can expire during the capture. When sdkTimeout is lower than or equal to cameraTimeout, the global timeout tends to end the session before the camera timeout, and the integration receives Action.Timeout with data = null even when the camera opened and the user waited for the time to run out.

Recommendation

When configuring both, keep sdkTimeout greater than cameraTimeout, with enough room for the instruction screen and for capture processing. Valid example: cameraTimeout = 120 and sdkTimeout = 300. If only cameraTimeout is configured, sdkTimeout stays at its 540-second default.

JSON Customization

JSON customization allows you to apply the SDK’s visual identity and texts using a .json file included in the integrator application's bundle.

Entry Function

The entry function for JSON customization is FortfaceSDK.setCustomization("file_name").

How to Configure

  1. Add the JSON file to the integrator project.
  2. Ensure the file is included in the app bundle under Copy Bundle Resources.
  3. Call FortfaceSDK.setCustomization using only the file name, without the .json extension.
FortfaceSDK.setCustomization("customization")

Attention

Use only one customization method per initialization.

  • If setCustomizer is called first, setCustomization will not be applied.
  • If setCustomization is called first, setCustomizer will not override the loaded configuration.

Expected Structure

The JSON file must declare the configurations directly at the root level using blocks such as:

  • theme
  • face_recognition
  • document_recognition
  • document_upload

Compatibility

Legacy configurations using the examples array are still supported by the SDK.

For new integrations, we recommend declaring the modules directly at the root of the JSON.

{
"version": "1.0.0",
"theme": {
"appearance": {
"font_family": "Poppins-SemiBold",
"background_color": "#FFFFFF",
"orientation": "automatic",
"modal": {
"enabled": false
}
}
},
"face_recognition": {
"instructions_screen": {
"visible": true,
"background_color": "#FAFAFA",
"title": {
"content": "Important tips\nfor your\nface photo!",
"color": "#332D41"
},
"topics": {
"messages": {
"no_items": {
"content": "Keep your face visible\nand remove items such as\nglasses and hats",
"color": "#332D41"
},
"well_lit": {
"content": "Find a well-lit\nlocation",
"color": "#332D41"
},
"neutral_expression": {
"content": "Keep a neutral\nexpression",
"color": "#332D41"
},
"straight_position": {
"content": "Position your phone\nat face level",
"color": "#332D41"
}
},
"icons": {
"color": "#00A594",
"background_color": "#F1F1F1"
}
},
"continue_button": {
"content": "Continue",
"background_color": "#00A594",
"text_color": "#FFFFFF",
"corner_radius": 10
}
},
"camera_screen": {
"background_color": "#FFFFFF",
"timeout": 30,
"min_stabilization_time": 1.0,
"max_stabilization_time": 2.0,
"close_button": {
"visible": true,
"position": "top-left"
},
"positioning_messages": {
"color": "#263238",
"frame_text_visible": true,
"loading_stroke_color": "#FFFFFF",
"content": {
"positioned": "Wait for validation,\ntry not to move",
"no_face": "Position your face inside the indicated area",
"face_far": "Move your face closer",
"face_near": "Move your face farther away",
"face_pitch_up": "Lower your face",
"face_pitch_down": "Raise your face",
"no_face_yaw": "Look forward",
"no_face_roll": "Keep your head straight",
"face_roll_left": "Tilt your head to the left",
"face_roll_right": "Tilt your head to the right",
"face_center_left": "Move the camera to the left",
"face_center_right": "Move the camera to the right",
"face_center_up": "Move the camera upward",
"face_center_down": "Move the camera downward"
}
},
"feedback_colors": {
"alert": "#FF9902",
"luminosity": "#24B8C2",
"success": "#5FC213"
},
"brightness_validation": {
"timeout": 10,
"messages": {
"too_dark": "Improve the lighting",
"too_bright": "Reduce the light on your face"
}
}
}
},
"document_recognition": {
"camera_screen": {
"timeout": 60,
"automatic_capture_timeout": 20,
"close_button": {
"visible": true,
"position": "top-right"
},
"feedback_colors": {
"neutral": "#F44336",
"success": "#9C27B0"
},
"positioning_messages": {
"color": "#FFFFFF",
"loading_stroke_color": "#FFFFFF",
"font": {
"family": "Poppins-SemiBold"
},
"content": {
"start": "Fit your document\ninside the frame",
"positioned": "Keep your phone steady",
"out_of_frame": "Position your document\ninside the indicated area",
"misaligned": "Keep your document straight",
"not_detected": "No document detected,\ntry positioning it again",
"too_far": "Move the camera closer\nto your document",
"too_near": "Move the camera farther\nfrom your document",
"capturing": "Do not move",
"wrong_face": "Show the back side of the document",
"tap_to_focus": "Tap the screen to focus"
}
},
"manual_capture_button": {
"content": "Take photo",
"background_color": "#00A594",
"text_color": "#FFFFFF",
"font": {
"family": "Poppins-SemiBold"
}
}
},
"review_screen": {
"title": {
"content": "Is your document\nclear and readable?",
"color": "#FFFFFF",
"font": {
"family": "Poppins-SemiBold"
}
},
"confirm_button": {
"content": "Yes, submit",
"background_color": "#367C14",
"text_color": "#FFFFFF"
},
"retry_button": {
"content": "Take another photo",
"background_color": "#B3261E",
"text_color": "#FFFFFF"
}
}
},
"document_upload": {
"review_screen": {
"background_color": "#FFFFFF",
"close_button": {
"visible": true,
"position": "top-right"
},
"title": {
"content": "Confirm your document",
"color": "#000000",
"font": {
"family": "Poppins-SemiBold"
}
},
"description": {
"content": "Your image must have\nclear and readable data with good quality.",
"color": "#AAAAAA",
"font": {
"family": "Poppins-Regular"
}
},
"confirm_button": {
"content": "Submit document",
"wait_message": "Please wait",
"background_color": "#00A594",
"text_color": "#FFFFFF",
"font": {
"family": "Poppins-SemiBold"
}
},
"retry_button": {
"content": "Upload again",
"text_color": "#00A594",
"font": {
"family": "Poppins-SemiBold"
}
}
}
}
}

Accepted Fields

FieldDescription
theme.appearance.font_familyDefault font applied to supported texts and buttons.
theme.appearance.background_colorDefault background color for supported screens.
theme.appearance.orientationSDK orientation: automatic, portrait, or landscape.
theme.appearance.modal.enabledDefines modal (true) or fullscreen (false) presentation.
face_recognition.instructions_screenCustomizes the face capture instruction screen.
face_recognition.camera_screenCustomizes the face capture camera screen.
document_recognition.camera_screenCustomizes the document capture camera screen.
document_recognition.review_screenCustomizes the document capture review screen.
document_upload.review_screenCustomizes the document upload review screen.

Notes

  • Colors must be provided in hexadecimal format, for example #00A594.
  • The name passed to setCustomization must match the resource name in the bundle without the .json extension.
  • Missing fields keep the SDK default values.
  • On iOS, font.size and font.weight may exist in the JSON, but only font.family is applied to supported fields.
  • For images, such as face_recognition.camera_screen.logo, provide either the name of an asset from the integrator app or a base64 image.

In addition to interface customizations, we also have the option to use our SDK in modal or fullscreen opening, both working in both portrait and landscape orientation, with responsiveness adapting to the selected scenario.

The SDK is displayed in full-screen mode in vertical (portrait) orientation by default on all supported devices. On tablets, it is possible to configure the orientation to horizontal (landscape) or automatic, allowing the SDK to adjust to the device's orientation, in addition to configuring for modal display.

Examples

Modal portraitModal landscape

Modo Fullscreen (Portrait e Landscape) - Valor padrão

Fullscreen portraitFullscreen landscape

To configure these modes, you need to change the following attributes:

Kotlin

1-Activating modal mode

customizer.screenMode = ScreenMode.Modal

2-Activating fullscreen mode

customizer.screenMode = ScreenMode.FullScreen

3-Orientation

customizer.screenOrientation = ScreenOrientation.Automatic customizer.screenOrientation = ScreenOrientation.Landscape customizer.screenOrientation = ScreenOrientation.Portrait