The GFS widgets use a new web technology, known as web components, to define custom HTML tags. Behind these lies all of the HTML, JavaScript and CSS needed to drive the Checkout flow within a website. Using them is as simple as including two files on the webpage that will contain the Checkout UI, and then adding the tags and attributes. Each element is described in detail in the following sections, and for each widget there's a live demo showing the HTML markup required to display the widget, and then the results. These can be edited, in real-time, in your browser, with the results immediately visible. When you're happy with the results the code can be cut and paste into your website.
The GFS Checkout widgets are built using web components, which are part of the very latest web standards, and are only supported by the very latest browsers. To allow support for the widgets on the widest range of browser versions, it is necessary to use a 'polyfill' library, which adds support for the missing functions into older browsers. We recommend using the webcomponentsjs "polyfill" library, which is automatically installed using the widget npm packages and can be linked in your HTML files using the code below.
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
Additionally, you may experience some odd behaviour in various browsers if you use bootstrap and include webcomponents first. We recommend loading webcomponents after all other libraries have been loaded.
To intialise the checkout widget, the following widget attributes should be set.
Attribute | Description |
---|---|
checkout-token | The Java Web Token (JWT) provided by the identity server to enable the widget to communicate with the GFS Checkout servers. See the security section for more information on authentication and obtaining this token. (MANDATORY) |
checkout-request | This attribute is used to populate the cart and order details in the widget, so that the best delivery options can be presented. (MANDATORY). See checkout-request for more information. |
currency-symbol | The currency symbol to use when displaying costs. (NOT MANDATORY, if not supplied "$" is used) |
default-delivery-method | The delivery method of the default service to be offered in case to the customer in the event that the widget cannot contact the GFS Checkout servers. (NOT MANDATORY, If not supplied "Standard" is used) |
default-description | The name of the default service to be offered to the customer in the event that the widget cannot contact the GFS Checkout servers. |
default-carrier | The default carrier to be offered to the customer in the event that the widget cannot contact the GFS Checkout server. |
default-price | The price of the default service to be offered to the customer in the event that the widget cannot contact the GFS Checkout server. |
default-min-delivery-time | The minimum delivery time in days of the default service to be offered to the customer in the event that the widget cannot contact the GFS Checkout server. |
default-max-delivery-time | The maximum delivery time in days of the default service to be offered to the customer in the event that the widget cannot contact the GFS Checkout server. |
Sample gfs-checkout widget attributes:
<gfs-checkout use-standard use-calendar use-droppoints inc-std inc-day-def inc-drop-point
checkout-token="ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKU1V6STFOaUlzSW5nMWRDSTZJa1pXWmtObFJGSlNaa2RHWkRCWVFuWlBTbXBZWDJ0eE5qRlNSU0lzSW10cFpDSTZJa1pXWmtObFJGSlNaa2RHWkRCWVFuWlBTbXBZWDJ0eE5qRlNSU0o5LmV5SnBjM01pT2lKb2RIUndjem92TDJsa1pXNTBhWFI1TG1wMWMzUnphRzkxZEdkbWN5NWpiMjBpTENKaGRXUWlPaUpvZEhSd2N6b3ZMMmxrWlc1MGFYUjVMbXAxYzNSemFHOTFkR2RtY3k1amIyMHZjbVZ6YjNWeVkyVnpJaXdpWlhod0lqb3hOVGM1T0RrMU1UWTRMQ0p1WW1ZaU9qRTBOems0T1RVeE5qa3NJbU5zYVdWdWRGOXBaQ0k2SW1GdFltbDBhVzkxYzE5aGJHbGpaU0lzSW1SbGRpMWhjR2t0YTJWNUlqb2lRMHd0TkVORk9USTJNVE10T0RsQk5pMDBNalE0TFVFMU56TXRRVGxCTnpNek0wVTJRVEEySWl3aWRHVnpkQzFoY0drdGEyVjVJam9pUTB3dE5EVXdNRVpETVVFdE4wUkROQzAwTjBGQ0xVRkZPVEl0UlRFME1qWkZNVEU1TVRsQ0lpd2liR2wyWlMxaGNHa3RhMlY1SWpvaVEwd3RORU5GT1RJMk1UTXRPRGxCTmkwME1qUTRMVUUxTnpNdFFUbEJOek16TTBVMlFUQTJJaXdpYzJOdmNHVWlPbHNpWTJobFkydHZkWFF0WVhCcElpd2ljbVZoWkNKZGZRLklSLTBOU2lpYk1rWWdzN3cyUE5oM29VS0Z1NHFqRGxBMjZfYXV1Nmg5ZDlyNGs3Y3pwdXZ6VFBsS1ZZMEE1U0dVOW81MmU1cHVoUzFuVnBWMmo0QnFMS3RBaEVqdktpMWw2ellDUS1ObmtiMlRRSFJEZ2VhMXZTT1h2T3dJNkxxbVlCbHptUnBQZG9PTUVMWTFhZ3pjYi1jNTRYend2eGRtb1g4MFNXQVZpN0dqVFdrV2ZkOVY3VGNsMTJSWjJ5M2RDeWtGUmRFN19ycHZiTGswQWZETGtubUlhZVV0MGFKTHY5bllaSWNzWGZxcEZwT0xMNmhyRHBZV3VmRUdibUk2S283QzV3TDdYWmtRR0o1aWpsUEZwRUJGOV90UjZMWW1vV3FwT3huUF9VVWp0b1daU05IRzQxMTlObnA2VHRJaVNpZ2dJQlFUaG1HTVhEU2ZHcEtBTGJzRjF4azdPWF9FUmNiS0dxWVczQXN5Q0ZGN0FLeFRIVkVhNlNBREhCWHFDeU5IVzdvOVJlS3JXa2pESk1TOHpkNjAxLVE3aXZfNU03SHNvb2xyeGRJbUdldEt6RGZYczVRVURzNE1VREhha0RGN2xlR2otSnpWeDM5aml6a2otZ1R6dG5OV3dWZ2F3ay1xeHA4cTMwU0VKbmpMYmstTWxWTHdZZl9nd2ROcE96LXVFQmEycVdkMWFlc09lR0dUem55WnpmX24xVUMzV3ZJMmFqSDk4YVU0a1FPYnY4Z1paRGU4TEo0QWZBRzBOYVdEUGNSNmRCTWJUMWN3TlY0RDBYSjBoQWMxdzRuN3dYMDR3cWY5aWFIMnF1bEZfZERFakl4dlVuYjBiQkF1YWduenpSREpZZTZERGtxWUhkYUxwMklYOUtRT04xNGx4dll5aHNIWkZV"
checkout-request="eyJSZXF1ZXN0Ijp7IkRhdGVSYW5nZSI6eyJEYXRlRnJvbSI6IjIwMTYtMTEtMjMiLCJEYXRlVG8iOiIyMDE2LTEyLTA3In0sIk9yZGVyIjp7IlRyYW5zaXQiOnsiUmVjaXBpZW50Ijp7ImNvbnRhY3REZXRhaWxzIjp7IkVtYWlsIjoibWluYXMucGFjaG5pc0BqdXN0c2hvdXRnZnMuY29tIn0sIkxvY2F0aW9uIjp7ImFkZHJlc3NMaW5lQ29sbGVjdGlvbiI6WyIxMDAgU3RhdGlvbiBSb2FkIl0sIkNvdW50cnlDb2RlIjp7IkNvZGUiOiJHQiIsIkVuY29kaW5nIjoiY2NJU09fMzE2Nl8xX0FscGhhMiJ9LCJQb3N0Y29kZSI6IlJIMTMgNVVaIiwidG93biI6IkhvcnNoYW0ifSwiUGVyc29uIjp7ImZpcnN0TmFtZSI6IkEiLCJsYXN0TmFtZSI6IkN1c3RvbWVyIiwidGl0bGUiOiJNUiJ9fX0sIlZhbHVlIjp7IkN1cnJlbmN5Q29kZSI6IkdCUCIsIlZhbHVlIjo0NS45OX19LCJSZXF1ZXN0ZWREZWxpdmVyeVR5cGVzIjpbImRtRHJvcFBvaW50IiwiZG1TdGFuZGFyZCJdLCJTZXNzaW9uIjp7IkFQSUtleUlkIjoiQ0wtNENFOTI2MTMtODlBNi00MjQ4LUE1NzMtQTlBNzMzM0U2QTA2In19fQ=="
default-delivery-method="0"
currency-symbol="£"
default-description="Standard Delivery"
default-carrier="YODEL"
default-price='[{"currency": "GBP", "price": 2.22}]'
default-min-delivery-time="3"
default-max-delivery-time="6">
</gfs-checkout>
The checkout-request attribute of the widget must contain a Base64 encoded JSON string containing the following information:
Field Name | Required | Example value |
---|---|---|
options.startDate | Mandatory | 2021-01-14 |
options.endDate | Mandatory | 2021-03-23 |
options.currency | Mandatory | GBP |
options.droppoints.max | Optional | 20 |
options.droppoints.radius | Optional | 50000 |
options.stores.max | Optional | 30 |
options.stores.radius | Optional | 30000 |
order.delivery.origin.street | Optional | GFS, Piries Place |
order.delivery.origin.city | Optional | Horsham |
order.delivery.origin.state | Optional | West Sussex |
order.delivery.origin.zip | Mandatory | RH12 1EH |
order.delivery.origin.country | Mandatory | GB |
order.delivery.destination.street | Optional | GFS, Unit 3 Taurus Park |
order.delivery.destination.city | Optional | Warrington |
order.delivery.destination.state | Optional | Cheshire |
order.delivery.destination.zip | Mandatory | WA5 7ZT |
order.delivery.destination.country | Mandatory | GB |
order.packs | Optional | 15 |
order.price | Mandatory | 165.32 |
order.additionalData[x].name | Optional | Additionalvaluename123 |
order.additionalData[x].value | Optional | Mandatory for every order.additionalData[0].name provided |
order.items[X].countryOfManufacture | Optional | EU |
order.items[X].description | Mandatory | Item description free text |
order.items[X].price | Mandatory | 11.25 |
order.items[X].dimensions.unit | Optional | cm |
order.items[X].dimensions.length | Optional | 15 |
order.items[X].dimensions.height | Optional | 56 |
order.items[X].dimensions.width | Optional | 24 |
order.items[X].weight.unit | Optional | g |
order.items[X].weight.value | Optional | 764 |
order.items[X].productCode | Mandatory | ProdCode123 |
order.items[X].sku | Optional | SKU-123 |
order.items[X].quantity | Mandatory | 15 |
order.items[X].additionalData[x].name | Optional | Additionalitemvaluename123 |
order.items[X].additionalData[x].value | Optional | Mandatory for every order.items[X].additionalData[0].name provided |
order.items[X].hazardous[X] | Optional | Hazard-C3 |
{
"options": {
"startDate": "",
"endDate": "",
"currency": ""
},
"order": {
"delivery": {
"origin": {
"zip": "",
"country": ""
},
"destination": {
"zip": "",
"country": ""
}
},
"price": ,
"items": [
{
"description": "",
"price": ,
"productCode": "",
"quantity":
}
]
}
}
To retrieve the selected delivery options from the checkout widget, the developer will need to close the current checkout session. As a security precaution that checkout session must be closed server side. The developer will need to add two hidden elements, checkoutResults and sessionID. These hidden fields will be used to store the data so the backend can retrieve it.
The ID’s of the hidden elements must have the same name as the widget properties.
Hidden fields:
<input type="hidden" name="gfsCheckoutResult" id="gfsCheckoutResult" />
<input type="hidden" name="gfsSessionID" id="gfsSessionID" />
<input type="hidden" name="gfsCheckoutData" id="gfsCheckoutData" />
Checkout widget:
<gfs-checkout checkout-results="gfsCheckoutResult" sessionid="gfsSessionID" checkout-data="gfsCheckoutData"></gfs-checkout>
Close checkout via a div:
<div id="closeCheckout" class="btn btn-block btn-primary">Checkout »</div>
The div that will show the error
<div id="service-error"></div>
Below we have the stored data that has been encoded using base-64 encoding.
Example 1:
<input type="hidden" name="gfsCheckoutResult" id="gfsCheckoutResult" value="UzM=">
If you decode the above checkoutResult it will return:
"S3"
Example 2:
<input type="hidden" name="gfsSessionID" id="gfsSessionID" value="NzM3MTY4ODYtZmMwOS00YjQ4LTk3MmMtNzQ5ZjBjNjgyNDMw">
If you decode the above example, it will return:
"73716886-fc09-4b48-972c-749f0c682430"
Example 3:
<input type="hidden" name="gfsCheckoutData" id="gfsCheckoutData" value="eyJjaGVja291dFNlbGVjdGVkU2VydmljZU5hbWUiOiJTdGFuZGFyZCBEZWxpdmVyeSIsImNoZWNrb3V0U2VsZWN0ZWREcm9wcG9pbnRBZGRyZXNzIjpudWxsLCJ0eXBlIjoiaG9tZSJ9">
If you decode the above example, it will return:
{"checkoutSelectedServiceName":"Standard Delivery","checkoutSelectedDroppointAddress":null,"type":"home"}
In the first example, the user has selected a service and the widget returns the selected service unique identifier. In the second example, the value is the 'sessoinID' and is important for closeChekcout method. In the third example, there are informations for the selected service, name, the type and the droppoint address as it shows on the page, not needed for closeCheckout.
Here is simple jQuery code to get the value from the checkoutResult input and check if there is an error.
$("#closeCheckout").click(function (e) {
var checkoutResult = $("#gfsCheckoutResult").val();
var obj = atob(checkoutResult);
var form = $("#checkoutForm");
if (obj != "") {
form.submit();
}
else {
var error = $("#service-error");
error.text("You must select one service method");
error.delay(150).slideDown("slow").delay(4000).slideUp("slow");
return;
}
});
When the form is submitted a DELETE method call must be made to the checkout API closing the checkout session. The DELETE method expects the sessionID (example 2) and the selected service type (example 1).
The code example below shows how to close the checkout session via .NET.
var accessToken = CheckoutAuthenticationHelper.GetCheckoutAccessToken();
var checkoutResult = Encoding.ASCII.GetString(Convert.FromBase64String(values["checkoutResult"]));
var sessionid = Encoding.ASCII.GetString(Convert.FromBase64String(values["sessionID"]));
string requestUrl = @"https://connect2.gfsdeliver.com/api/checkout/session/" + sessionid + "/" + checkoutResult;
var client = new HttpClient();
client.BaseAddress = new Uri(requestUrl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.AccessToken);
var method = new HttpMethod("DELETE"); // create the PATCH method
HttpContent httpContent = new StringContent(checkoutResult, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(method, requestUrl);
request.Content = httpContent;
HttpResponseMessage responseMsg = await client.SendAsync(request);
var responseService = await responseMsg.Content.ReadAsStringAsync();
dynamic response = JsonConvert.DeserializeObject<ReturnedDetails>(responseService); // get the reponse from the API
The code example below shows how to close the checkout session via PHP.
$request_body = parse_str(file_get_contents('php://input'), $_GET);
$checkoutResult = base64_decode($_POST['checkoutResult']);
$sessionid = base64_decode($_POST['sessionID']);
$endpoint = "https://connect2.gfsdeliver.com/api/checkout/session/" . $sessionid . "/" . $checkoutResult;
$headers = array(
'Content-Type:application/json',
'Authorization: Bearer ' . $accesToken
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $endpoint);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);